gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-exchange] branch stable updated (bf1fc00a -> 105555b


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] branch stable updated (bf1fc00a -> 105555b4)
Date: Wed, 08 May 2019 06:24:53 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch stable
in repository exchange.

    from bf1fc00a Bug annotation
     add a827ee9b typo
     add 8d979a92 syntax
     add 9d37f8e0 keyup:_use_ the timestamp given by the user.
     add 8e656ca9 fix git link to GNUnet repo
     add 41afe6fd fix git link to Taler repo
     add 219f7029 Faking the time.
     add 35c064b9 Faking the time.
     add 6e6ce685 Provide API to fake now when requesting /keys.
     add dc7d74ca fix keyup invocation.
     add ccd43ba4 gitignore
     add ce71d83a Provide testing API to fake now for "/keys".
     add 3e757cde Inserting "now" argument into "/keys".
     add 32cdef2b Making the bug /history[-range] args parser.
     add a19baacc Do not include legally expired keys into /keys response.
     add 8655a40a Half-baking #5666.
     add fdeb6301 Artificial 'now'.
     add 301f287b Test the big lookahead_sign, plus notes.
     add 5e16b871 Improving the math.
     add 8b3ee471 fix #includes
     add 6b6417b1 doc/taler-exchange.texi: Fix build with older Texinfo 
versions.
     add eca27d9d Finish abstract history builder.
     add 3c66bb30 Gather /history implementation(s) in one point.
     add ddb8cdfa Finishing /history-range implementation, untested.
     add 704e0913 Fix compilation warnings, + enable polymorphic /history 
handler.
     add e24e845b debug message
     add 9fc380f7 Set range pointer.
     add e13a8902 Put /history[-range] logic in a dedicate file.
     add 602093e9 notes
     add 0b8a8712 Refactor auditor/taler-auditor.c for GNUNET_memcmp
     add 79dcb727 Refactor auditor/taler-wire-auditor.c for GNUNET_memcmp
     add d55c2acb refactor util/test_crypto.c for GNUNET_memcmp
     add a5007df7 refactor for GNUNET_memcmp
     add cf62f519 refactor for GNUNET_memcmp
     add 391895d8 Refactor test_auditordb.c for GNUNET_memcmp
     add d77bf8ab Refactor for GNUNET_memcmp and _is_zero
     add 9f18ec58 Refactor for GNUNET_memcmp
     add ffac5413 Refactor for GNUNET_memcmp
     add 8e4df341 Refactor for GNUNET_memcmp
     add 7333c55c Fix leftover memcmp
     add b669f0df Refactor plugin_exchangedb_postgres for GNUNET_memcmp
     add 8c591b4f Refactor lib/exchange_api_common.c for GNUNET_memcmp
     add 1aa9d9fe Refactor lib/exchange_api_reserve.c for GNUNET_memcmp
     add 04acf37c Refactor test_exchangedb_signkeys for GNUNET_memcmp
     add 5ec20870 Refactor test_exchangedb_denomkeys.c for GNUNET_memcmp
     add ed0da1fd /history-range.
     add 074b011d exchangedb/exchangedb_test: GNUNET_memcmp
     add 7bebb3c7 Refactor testing_api_cmd_payback for GNUNET_memcmp
     add b7b53da0 Refactor exchange_api_handle for GNUNET_memcmp
     add f54d6294 Refactor test_exchangedb_auditors for GNUNET_memcmp
     add 2699155b Refactor test_exchangedb_denomkeys for GNUNET_memcmp
     add f3d80b58 Make the API-agnostic iterator work.
     add 75ac6b80 minor fixes
     add 814522d2 Time math macros.
     add ca718b9f minor fixes
     add 5c496633 Fixing twisted tests.
     add 66425084 Test /history-range after transactions happened.
     add a73e1dd4 fix docu: section name changed
     add 71acaff2 Merge branch 'master' of git.taler.net:exchange
     add 123d5077 fix build trouble
     add 0d375880 Better calculation of # DKs
     add 12aa5160 Fix history CMD loop, + make fakebank demonize.
     add 2025e116 Address compilation warnings.
     add 25f444a3 Address compilation warnings.
     add ba4ded3d Re-enabling keys serialization test.
     add 9b33452a Introduce new "history range" wire API.
     add 054fe2fb Address more warnings on types.
     add c93e699d Still on making the compiler happy.
     add a02af1f5 Refactor test_exchangedb for GNUNET_memcmp
     add c1d6806b Refactor for GNUNET_memcmp
     add 28123fd1 Refactor for GNUNET_memcmp
     add ee9cff35 Refactor for GNUNET_memcmp
     add 1fdec6b1 Refactor for GNUNET_memcmp
     add 5d3ae965 Wire plugin.
     add 32a3a0ff add post HTTP request check for hanging transactions
     add d82068a1 memcmp
     add 3cf3c580 memcmp
     add 4c9c7482 Install taler-bank-transfer again.  Needed by reserve topper.
     add 9c515d21 use uint64_t for serial_id
     add ddea1bf4 refactor link_bc() for GNUnet_memcmp
     add e1cf1a48 refactor for GNUnet_memcmp
     add 13cf7ee0 refactor for GNUNET_memcmp
     add 4bfd8bcd del
     add 4cd340e5 fix madness in configure.ac
     add 6e33de94 Merge branch 'master' of git.taler.net:exchange
     add 0d8f5035 doc: rewrite.
     add cce67665 save and restore CFLAGS/LDFLAGS/LIBS when checking for 
gnurl/curl
     add 8e391e8b Don't free null strings.
     add 88f9e693 benchmar: wait for exchange worker to terminate
     add feec6e30 benchmark: terminate exchange slave properly
     add d821ecc3 Remove bogus ifdef for tcp fast open
     add de9fdf86 replace denom_pub with denom_pub_hash in exchange API to 
reduce bandwidth
     add 9c194f79 adapt to GNUnet API change
     add 5dd3c219 benchmark: don't print result as exchange worker
     add a16c32a4 add compression support for bodies of POST/PUT operations
     add 105555b4 Merge branch 'master' of git.taler.net:exchange

No new revisions were added by this update.

Summary of changes:
 .gitignore                                         |   2 +
 ChangeLog                                          |   9 +
 configure.ac                                       |  88 ++--
 doc/logos/eps/logo_taler.eps                       | Bin 10731812 -> 0 bytes
 doc/taler-auditor-exchange.1                       |  77 +--
 doc/taler-auditor-sign.1                           |  80 +--
 doc/taler-auditor.1                                |  70 +--
 doc/taler-bank-transfer.1                          |  91 ++--
 doc/taler-config-generate.1                        | 119 ++---
 doc/taler-exchange-aggregator.1                    |  63 +--
 doc/taler-exchange-benchmark.1                     |  79 +--
 doc/taler-exchange.texi                            |  34 +-
 doc/taler.conf.5                                   | 472 +++++++++---------
 src/auditor/taler-auditor-httpd_parsing.c          |   1 +
 src/auditor/taler-auditor.c                        | 102 ++--
 src/auditor/taler-wire-auditor.c                   |  10 +-
 src/auditordb/test_auditordb.c                     |  78 ++-
 src/bank-lib/Makefile.am                           |   3 +-
 src/bank-lib/bank_api_admin.c                      |   4 +
 src/bank-lib/bank_api_history.c                    | 334 +++++++++----
 src/bank-lib/fakebank.c                            | 538 +++++++--------------
 src/bank-lib/fakebank.h                            | 322 ++++++++++++
 src/bank-lib/fakebank_history.c                    | 427 ++++++++++++++++
 src/bank-lib/taler-bank-transfer.c                 |   2 +
 src/bank-lib/test_bank_api_new.c                   |  53 +-
 src/bank-lib/test_bank_api_twisted.c               |  38 +-
 src/bank-lib/test_bank_api_with_fakebank_new.c     |   6 -
 src/bank-lib/test_bank_api_with_fakebank_twisted.c |  36 +-
 src/bank-lib/test_bank_interpreter.c               |   2 +
 src/bank-lib/testing_api_cmd_history.c             | 390 +++++++++++++--
 src/benchmark/taler-exchange-benchmark.c           |  37 +-
 src/exchange-tools/taler-exchange-keycheck.c       |   5 +-
 src/exchange-tools/taler-exchange-keyup.c          |  49 +-
 src/exchange-tools/taler-wire.c                    |   4 +-
 src/exchange/taler-exchange-aggregator.c           |  16 +-
 src/exchange/taler-exchange-httpd.c                |   6 +
 src/exchange/taler-exchange-httpd_db.c             |  30 +-
 src/exchange/taler-exchange-httpd_deposit.c        |  84 ++--
 src/exchange/taler-exchange-httpd_keystate.c       |  94 ++--
 src/exchange/taler-exchange-httpd_keystate.h       |   9 +-
 src/exchange/taler-exchange-httpd_parsing.c        |   1 +
 src/exchange/taler-exchange-httpd_payback.c        |  23 +-
 src/exchange/taler-exchange-httpd_refresh_melt.c   |  42 +-
 src/exchange/taler-exchange-httpd_refresh_reveal.c |   8 +-
 src/exchange/taler-exchange-httpd_refund.c         |   8 +-
 .../taler-exchange-httpd_reserve_withdraw.c        |  24 +-
 src/exchange/taler-exchange-httpd_responses.c      |   5 +-
 src/exchange/taler-exchange-httpd_track_transfer.c |  10 +-
 src/exchange/test_taler_exchange_aggregator.c      |   3 +-
 src/exchangedb/exchangedb_denomkeys.c              |   2 +-
 src/exchangedb/perf_taler_exchangedb_init.c        |  28 +-
 src/exchangedb/perf_taler_exchangedb_interpreter.c |   5 +-
 src/exchangedb/plugin_exchangedb_common.c          |  10 -
 src/exchangedb/plugin_exchangedb_postgres.c        | 131 +++--
 src/exchangedb/test_exchangedb.c                   | 190 +++-----
 src/exchangedb/test_exchangedb_auditors.c          |  20 +-
 src/exchangedb/test_exchangedb_denomkeys.c         |  10 +-
 src/exchangedb/test_exchangedb_signkeys.c          |   5 +-
 src/include/taler_bank_service.h                   |  37 ++
 src/include/taler_crypto_lib.h                     |  10 +-
 src/include/taler_exchange_service.h               |  20 +
 src/include/taler_exchangedb_plugin.h              |   9 +-
 src/include/taler_testing_bank_lib.h               |  57 +++
 src/include/taler_testing_lib.h                    | 125 ++++-
 src/include/taler_wire_plugin.h                    |  24 +
 src/lib/Makefile.am                                |   9 +-
 src/lib/auditor_api_curl_defaults.c                |   2 -
 src/lib/auditor_api_deposit_confirmation.c         |  39 +-
 src/lib/auditor_api_handle.c                       |  12 +-
 src/lib/auditor_api_handle.h                       |   2 +-
 src/lib/exchange_api_common.c                      |   5 +-
 src/lib/exchange_api_curl_defaults.c               |   2 -
 src/lib/exchange_api_deposit.c                     |  43 +-
 src/lib/exchange_api_handle.c                      | 144 ++++--
 src/lib/exchange_api_handle.h                      |   2 +-
 src/lib/exchange_api_payback.c                     |  34 +-
 src/lib/exchange_api_refresh.c                     |  67 +--
 src/lib/exchange_api_refund.c                      |  30 +-
 src/lib/exchange_api_reserve.c                     |  48 +-
 src/lib/exchange_api_track_transaction.c           |  32 +-
 src/lib/teah_common.c                              | 105 ++++
 src/lib/teah_common.h                              |  74 +++
 src/lib/test_exchange_api_interpreter_on-off.c     |   0
 src/lib/test_exchange_api_keys_cherry_picking.conf |  19 +
 .../test_exchange_api_keys_cherry_picking_new.c    | 219 +++++----
 src/lib/test_exchange_api_twisted.c                |  16 +-
 src/lib/testing_api_cmd_bank_check.c               |  24 +-
 src/lib/testing_api_cmd_check_keys.c               |  79 ++-
 src/lib/testing_api_cmd_exec_keyup.c               |  81 +++-
 src/lib/testing_api_cmd_fakebank_transfer.c        |  34 +-
 src/lib/testing_api_cmd_payback.c                  |   3 +-
 src/lib/testing_api_cmd_refresh.c                  |  14 +-
 src/lib/testing_api_cmd_sleep.c                    | 119 ++++-
 src/lib/testing_api_cmd_track.c                    |   5 +-
 src/lib/testing_api_loop.c                         |   1 -
 ...g_api_trait_wtid.c => testing_api_trait_time.c} |  37 +-
 src/util/crypto.c                                  |  17 +-
 src/util/test_crypto.c                             |  15 +-
 src/wire-plugins/plugin_wire_taler-bank.c          | 120 ++++-
 .../test_wire_plugin_transactions_taler-bank.c     |   5 +-
 100 files changed, 4101 insertions(+), 2028 deletions(-)
 delete mode 100644 doc/logos/eps/logo_taler.eps
 create mode 100644 src/bank-lib/fakebank.h
 create mode 100644 src/bank-lib/fakebank_history.c
 create mode 100644 src/lib/teah_common.c
 create mode 100644 src/lib/teah_common.h
 mode change 100755 => 100644 src/lib/test_exchange_api_interpreter_on-off.c
 copy src/lib/{testing_api_trait_wtid.c => testing_api_trait_time.c} (64%)

diff --git a/.gitignore b/.gitignore
index 82e95c25..6f7a0258 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ doc/doxygen/doxygen_sqlite3.db
 src/auditor/taler-auditor
 src/auditor/taler-auditor-dbinit
 src/auditor/taler-auditor-sign
+src/bank-lib/taler-fakebank-run
 src/bank-lib/test_bank_api
 src/bank-lib/test_bank_api_new
 src/bank-lib/test_bank_api_with_fakebank
@@ -114,3 +115,4 @@ src/bank-lib/test_bank_api_twisted
 src/lib/test_exchange_api_new
 src/lib/test_auditor_api
 src/lib/test_exchange_api_overlapping_keys_bug
+src/lib/test_exchange_api_home/.local/share/taler/exchange/revocations/
diff --git a/ChangeLog b/ChangeLog
index 5fce75ec..a5ab93af 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Fri 03 May 2019 05:36:10 PM CEST
+    Add support for compressing bodies during HTTP uploads to
+    exchange and auditor. -CG
+
+Thu 02 May 2019 09:15:37 PM CEST
+    Pass hash of denomination public key in operations from
+    clients to exchange instead of the (larger) full public key.
+    Breaks protocol compatibility, bumping protocol to v3. -CG
+
 Mon Mar 11 03:24:07 CET 2019
        Completed implementation of #5536 (delete private keys once we
        no longer need them). -CG
diff --git a/configure.ac b/configure.ac
index ae0dda1a..3c1d9dd3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -180,43 +180,42 @@ AS_IF([test $libgnunetjson != 1],
 *** ]])])
 
 
-# libcurl-gnutls
-LIBCURL_CHECK_CONFIG(,7.34.0,[curl=true],[curl=false])
-AS_IF([test "x$curl" = xtrue],
-      [LDFLAGS="-L$with_libcurl/lib $LDFLAGS"
-       CPPFLAGS="-I$with_libcurl/include $CPPFLAGS"
-       AC_CHECK_HEADERS([curl/curl.h],
-                        [AC_CHECK_DECLS(CURLINFO_TLS_SESSION,
-                         [curl=true],
-                         [curl=false],
-                         [[#include <curl/curl.h>]])],
-                        [curl=false])
-       # need libcurl-gnutls.so, everything else is not acceptable
-       AC_CHECK_LIB([curl-gnutls],
-                    [curl_easy_getinfo],,
-                    [curl=false])])
-       # cURL must support CURLINFO_TLS_SESSION, version >= 7.34
-
-# Check for curl/curl.h and gnurl/curl.h so we can use #ifdef
-# HAVE_CURL_CURL_H later (the above LIBCURL_CHECK_CONFIG accepted
-# *either* header set).
-AC_CHECK_HEADERS([curl/curl.h],,
-  curl=false
-  AC_CHECK_HEADERS([gnurl/curl.h],,
-  gnurl=false))
+# Save before checking libgnurl/libcurl
+CFLAGS_SAVE=$CFLAGS
+LDFLAGS_SAVE=$LDFLAGS
+LIBS_SAVE=$LIBS
 
+# check for libgnurl
 # libgnurl
-AS_IF([test "x$gnurl" = "x0"],
-      [AS_IF([test "x$curl" = "x0"],
-              [AC_MSG_NOTICE([NOTICE: libgnurl not found. taler-bank support 
will not be compiled.])],
-              [AC_MSG_NOTICE([WARNING: libgnurl not found, trying to use 
libcurl-gnutls instead.])])])
-
-AS_IF([test x$curl = xfalse],
-       [AM_CONDITIONAL(HAVE_LIBCURL, false)
-        AS_IF([test "x$gnurl" = "x0"],
-              [AC_MSG_WARN([GNU Taler requires libcurl-gnutls  >= 7.34])])],
-       [AM_CONDITIONAL(HAVE_LIBCURL, true)
-       AC_DEFINE([HAVE_LIBCURL],[1],[Have CURL])])
+LIBGNURL_CHECK_CONFIG(,7.34.0,gnurl=1,gnurl=0)
+LIBCURL_CHECK_CONFIG(,7.34.0,[curl=1],[curl=0])
+
+if test "x$curl" = x1
+then
+ AC_CHECK_HEADER([curl/curl.h],
+  AC_CHECK_DECLS(CURLINFO_TLS_SESSION,[curl=1],[curl=0],[[#include 
<curl/curl.h>]]),
+  [curl=0])
+ # need libcurl-gnutls.so, everything else is not acceptable
+ AC_CHECK_LIB([curl-gnutls],[curl_easy_getinfo],,[curl=0])
+ # cURL must support CURLINFO_TLS_SESSION, version >= 7.34
+fi
+
+# libcurl and libgnurl should be mutually exclusive
+AS_IF([test "$gnurl" = 1],
+      [AM_CONDITIONAL(HAVE_LIBGNURL, true)
+       AC_DEFINE([HAVE_LIBGNURL],[1],[Have libgnurl])
+       AM_CONDITIONAL(HAVE_LIBCURL, false)
+       AC_DEFINE([HAVE_LIBCURL],[0],[Lacking libcurl])],
+      [AS_IF([test "$curl" = 1],
+             [AM_CONDITIONAL(HAVE_LIBGNURL, false)
+              AC_DEFINE([HAVE_LIBGNURL],[0],[Lacking libgnurl])
+              AM_CONDITIONAL(HAVE_LIBCURL, true)
+              AC_DEFINE([HAVE_LIBCURL],[1],[Have libcurl])],
+             [AC_MSG_WARN([WARNING: No libgnurl/libcurl, taler-bank support 
will not be compiled])
+              AM_CONDITIONAL(HAVE_LIBGNURL, false)
+              AC_DEFINE([HAVE_LIBGNURL],[0],[Lacking libgnurl])
+              AM_CONDITIONAL(HAVE_LIBCURL, false)
+              AC_DEFINE([HAVE_LIBCURL],[0],[Lacking libcurl])])])
 
 # Check for GNUnet's libgnunetcurl.
 libgnunetcurl=0
@@ -245,6 +244,10 @@ AS_IF([test $libgnunetcurl != 1],
 *** ]])])
 
 
+# Restore after gnurl/curl checks messed up these values
+CFLAGS=$CFLAGS_SAVE
+LDFLAGS=$LDFLAGS_SAVE
+LIBS=$LIBS_SAVE
 
 # Check for GNUnet's libgnunetpq.
 libgnunetpq=0
@@ -330,9 +333,9 @@ else
 
 CFLAGS_SAVE=$CFLAGS
 LDFLAGS_SAVE=$LDFLAGS
+LIBS_SAVE=$LIBS
 CFLAGS="$CFLAGS $LIBGCRYPT_CFLAGS"
 LDFLAGS="$LDFLAGS $LIBGCRYPT_LDFLAGS"
-LIBS_SAVE="$LIBS"
 LIBS="-lgcrypt -lgpg-error $LIBS"
 
 
@@ -383,19 +386,6 @@ LIBS_SAVE="$LIBS"
 
 AM_CONDITIONAL(HAVE_POSTGRESQL, test x$postgres = xtrue)
 
-# check for libgnurl
-# libgnurl
-LIBGNURL_CHECK_CONFIG(,7.34.0,gnurl=1,gnurl=0)
-if test "$gnurl" = 1
-then
-        LDFLAGS="-L$with_libgnurl/lib $LDFLAGS"
-        CPPFLAGS="-I$with_libgnurl/include $CPPFLAGS"
-       AM_CONDITIONAL(HAVE_LIBGNURL, [true])
-       AC_DEFINE([HAVE_LIBGNURL],[1],[Have libgnurl])
-else
-       AM_CONDITIONAL(HAVE_LIBGNURL, [false])
-fi
-
 CFLAGS=$CFLAGS_SAVE
 LDFLAGS=$LDFLAGS_SAVE
 LIBS=$LIBS_SAVE
diff --git a/doc/logos/eps/logo_taler.eps b/doc/logos/eps/logo_taler.eps
deleted file mode 100644
index 34312849..00000000
Binary files a/doc/logos/eps/logo_taler.eps and /dev/null differ
diff --git a/doc/taler-auditor-exchange.1 b/doc/taler-auditor-exchange.1
index c26cad7d..d038c37e 100644
--- a/doc/taler-auditor-exchange.1
+++ b/doc/taler-auditor-exchange.1
@@ -1,34 +1,45 @@
-.TH TALER\-AUDITOR\-EXCHANGE 1 "Nov 3, 2018" "GNU Taler"
-
-.SH NAME
-taler\-auditor\-exchange \- add or remove exchange from auditor's list
-
-.SH SYNOPSIS
-.B taler\-auditor\-exchange [--remove] -m EXCHANGE_KEY -u EXCHANGE_URL
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-auditor\-exchange\fP is a command line tool to be used by an auditor 
to add or remove an exchange from the list of exchange's audited by the 
auditor.  You must add an exchange to that list before signing denomination 
keys with taler\-auditor\-sign or trying to audit it with taler\-auditor or 
taler\-wire\-auditor.  Afterwards the exchange will be visible via the 
/exchanges API of the taler\-auditor\-httpd.
-
-.SH OPTIONS
-.B
-.IP "\-m MASTERKEY,  \-\-exchange-key=MASTERKEY"
-Public key of the exchange in Crockford base32 encoding, for example as 
generated by gnunet\-ecc \-p.
-.B
-.IP "\-h, \-\-help"
+.Dd November 3, 2018
+.Dd TALER-AUDITOR-EXCHANGE 1
+.Os
+.Sh NAME
+.Nm taler-auditor-exchange
+.Nd
+add or remove exchange from auditor's list
+.Sh SYNOPSIS
+.Nm
+.Op Fl h | \-help
+.Op Fl r | \-remove
+.Op Fl m Ar MASTERKEY | Fl \-exchange-key= Ns Ar MASTERKEY
+.Op Fl u Ar EXCHANGE_URL | Fl \-auditor-url= Ns Ar EXCHANGE_URL
+.Sh DESCRIPTION
+.Nm
+is a command line tool to be used by an auditor to add or remove an exchange 
from the list of exchange's audited by the auditor.
+You must add an exchange to that list before signing denomination keys with 
taler-auditor-sign or trying to audit it with taler-auditor or 
taler-wire-auditor.
+Afterwards the exchange will be visible via the /exchanges API of the 
taler-auditor-httpd.
+.Bl -tag -width Ds
+.It Fl m Ar MASTERKEY | Fl \-exchange-key= Ns Ar MASTERKEY
+Public key of the exchange in Crockford base32 encoding, for example as 
generated by gnunet-ecc -p.
+.It Fl h | \-help
 Print short help on options.
-.B
-.IP "\-u URL,  \-\-auditor-url=URL"
-URL of the exchange. The exchange's HTTP API must be available at this address.
-.B
-.IP "\-r,  \-\-remove"
-Instead of adding the exchange, remove it. Note that this will drop ALL data 
associated with that exchange, including existing auditing information.  So use 
with extreme care!
-
-.SH BUGS
-We should optionally verify the correctness of this exchange's base URL and 
that it matches the master public key (note that the exchange may still be 
offline, so it should be possible to bypass such a verfication step).  
Furthermore, if we do verification, as a (less secure) convenience option, we 
should make \-m optional and obtain it from the base URL.
-
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
-
-.SH "SEE ALSO"
-\fBtaler\-auditor\-sign\fP(1), \fBgnunet\-ecc\fP(1), \fBtaler.conf\fP(5)
+.It Fl u Ar EXCHANGE_URL | Fl \-auditor-url= Ns Ar EXCHANGE_URL
+URL of the exchange.
+The exchange's HTTP API must be available at this address.
+.It Fl r | \-remove
+Instead of adding the exchange, remove it.
+Note that this will drop ALL data associated with that exchange, including 
existing auditing information.
+So use with extreme care!
+.Sh SEE ALSO
+.Xr gnunet-ecc 1 ,
+.Xr taler-auditor-sign 1 ,
+.Xr taler.conf 5
+.Sh BUGS
+We should optionally verify the correctness of this exchange's base URL and 
that it matches the master public key (note that the exchange may still be 
offline, so it should be possible to bypass such a verfication step).
+Furthermore, if we do verification, as a (less secure) convenience option, we 
should make
+.Fl
+m
+optional and obtain it from the base URL.
+.Pp
+Report bugs by using
+.Lk https://gnunet.org/bugs/
+or by sending electronic mail to
+.Aq Mt address@hidden .
diff --git a/doc/taler-auditor-sign.1 b/doc/taler-auditor-sign.1
index e5883dbc..659dabca 100644
--- a/doc/taler-auditor-sign.1
+++ b/doc/taler-auditor-sign.1
@@ -1,40 +1,46 @@
-.TH TALER\-AUDITOR\-SIGN 1 "Mar 15, 2016" "GNU Taler"
-
-.SH NAME
-taler\-auditor\-sign \- Sign exchange denomination as auditor.
-
-.SH SYNOPSIS
-.B taler\-auditor\-sign
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-auditor\-sign\fP is a command line tool to be used by an auditor to 
sign that he is aware of certain keys being used by a exchange.  Using this 
signature, the auditor affirms that he will verify that the exchange is 
properly accounting for those coins.
-
+.Dd
+.Dt TALER\-AUDITOR\-SIGN 1 "Mar 15, 2016" "GNU Taler"
+.Os
+.Sh NAME
+.Nm taler\-auditor\-sign
+.Nd
+Sign exchange denomination as auditor.
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar FILE | Fl \-auditor-key= Ns Ar FILE
+.Op Fl h | \-help
+.Op Fl m Ar KEY | Fl \-exchange-key= Ns Ar KEY
+.Op Fl u Ar URL | Fl \-auditor-url= Ns Ar URL
+.Op Fl r Ar FILE | Fl \-exchange-request= Ns Ar FILE
+.Op Fl o Ar FILE | Fl \-output= Ns Ar FILE
+.Sh DESCRIPTION
+.Nm
+is a command line tool to be used by an auditor to sign that he is aware of 
certain keys being used by a exchange.
+Using this signature, the auditor affirms that he will verify that the 
exchange is properly accounting for those coins.
+.Pp
 The exchange for which keys were signed must have been added to the auditor 
using taler\-auditor\-exchange first!
-
-.SH OPTIONS
-.B
-.IP "\-a FILE,  \-\-auditor-key=FILE"
-Location of the private EdDSA auditor key.  If it does not exist, it will be 
created.
-.B
-.IP "\-h, \-\-help"
+.Bl -tag -width Ds
+.It Fl a Ar FILE | Fl \-auditor-key= Ns Ar FILE
+Location of the private EdDSA auditor key.
+If it does not exist, it will be created.
+.It Fl h | \-help
 Print short help on options.
-.B
-.IP "\-m KEY,  \-\-exchange-key=KEY"
-Public key of the exchange in Crockford base32 encoding, for example as 
generated by gnunet\-ecc \-p.
-.B
-.IP "\-u URL,  \-\-auditor-url=URL"
-URL of the auditor. Provides informative link for the user to learn more about 
the auditor.
-.B
-.IP "\-r FILE,  \-\-exchange-request=FILE"
-File with the exchange's denomination key signing request as generated by 
taler\-exchange\-keyup \-o.
-.B
-.IP "\-o FILE, \-\-output=FILE"
+.It Fl m Ar KEY | Fl \-exchange-key= Ns Ar KEY
+Public key of the exchange in Crockford base32 encoding, for example as 
generated by gnunet-ecc -p.
+.It Fl u Ar URL | Fl \-auditor-url= Ns Ar URL
+URL of the auditor.
+Provides informative link for the user to learn more about the auditor.
+.It Fl r Ar FILE | Fl \-exchange-request= Ns Ar FILE
+File with the exchange's denomination key signing request as generated by 
taler-exchange-keyup -o.
+.It Fl o Ar FILE | Fl \-output= Ns Ar FILE
 File where the auditor should write the EdDSA signature.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
-
-.SH "SEE ALSO"
-\fBtaler\-auditor\-exchange\fP(1), \fBtaler\-exchange\-keyup\fP(1), 
\fBgnunet\-ecc\fP(1), \fBtaler.conf\fP(5)
+.Sh SEE ALSO
+.Xr gnunet-ecc 1 ,
+.Xr taler-auditor-exchange 1 ,
+.Xr taler-exchange-keyup 1 ,
+.Xr taler.conf 5
+.Sh BUGS
+Report bugs by using
+.Lk https://gnunet.org/bugs/
+or by sending electronic mail to
+.Aq Mt address@hidden .
diff --git a/doc/taler-auditor.1 b/doc/taler-auditor.1
index dc4da238..c0b82d64 100644
--- a/doc/taler-auditor.1
+++ b/doc/taler-auditor.1
@@ -1,29 +1,43 @@
-.TH TALER\-AUDITOR 1 "Mar 20, 2017" "GNU Taler"
-
-.SH NAME
-taler\-auditor \- Audit exchange.
-
-.SH SYNOPSIS
-.B taler\-auditor -m MASTER_KEY
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-auditor\fP is a command line tool to be used by an auditor to audit 
an exchange's database and calculate the current financial state of the 
exchange (including revenue, amount expected in escrow and risk exposure).  The 
audit is incremental.  The first audit must be performed with the \-r option to 
initialize the tables.  The tool reports inconsistencies in the balance or 
incorrect cryptographic signatures found in the database.  It does NOT check 
with the bank to see that the  [...]
-
-.SH OPTIONS
-.B
-.IP "\-h, \-\-help"
+.Dd March 20, 2017
+.Dt TALER-AUDITOR 1
+.Os
+.Sh NAME
+.Nm taler-auditor
+.Nd
+Audit exchange
+.Sh SYNOPSIS
+.Nm
+.Op Fl h | \-help
+.Op Fl m Ar MASTER_KEY | Fl \-exchange-key= Ns Ar MASTER_KEY
+.Op Fl r | \-reset
+.Sh DESCRIPTION
+.Nm
+is a command line tool to be used by an auditor to audit an exchange's 
database and calculate the current financial state of the exchange (including 
revenue, amount expected in escrow and risk exposure).
+The audit is incremental.
+The first audit must be performed with the
+.Fl r
+option to initialize the tables.
+The tool reports inconsistencies in the balance or incorrect cryptographic 
signatures found in the database.
+It does NOT check with the bank to see that the incoming and outgoing wire 
transfers that the bank claims to have matches the exchange's database.
+Its options are as follows.
+.Bl -tag -wdith Ds
+.It Fl h | \-help
 Print short help on options.
-.B
-.IP "\-m KEY,  \-\-exchange-key=KEY"
-Public master key of the exchange in Crockford base32 encoding, for example as 
generated by gnunet\-ecc \-p.  If this option is missing, taler\-auditor will 
use the MASTER_PUBLIC_KEY value from the "exchange" section of the 
configuration.
-.B
-.IP "\-r,  \-\-reset"
-Reset the audit, starts everything from the beginning. Useful for testing and 
required for the first audit to setup auditor's tables. Note that if (just) the 
exchange key changes, the \-r option should not be used again.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
-
-.SH "SEE ALSO"
-\fBtaler\-auditor\-sign\fP(1), \fBgnunet\-ecc\fP(1), \fBtaler.conf\fP(5)
+.It Fl m Ar KEY | Fl \-exchange-key= Ns Ar KEY
+Public master key of the exchange in Crockford base32 encoding, for example as 
generated by gnunet-ecc -p.
+If this option is missing, taler-auditor will use the MASTER_PUBLIC_KEY value 
from the "exchange" section of the configuration.
+.It Fl r | \-reset
+Reset the audit, starts everything from the beginning.
+Useful for testing and required for the first audit to setup auditor's tables.
+Note that if (just) the exchange key changes, the
+.Fl r
+option should not be used again.
+.Sh SEE ALSO
+.Xr gnunet-ecc 1 ,
+.Xr taler-auditor-sign 1 ,
+.Xr taler.conf 5
+.Sh BUGS
+Report bugs by using
+.Lk https://bugs.gnunet.org
+or by sending electronic mail to
+.Aq Mt address@hidden .
diff --git a/doc/taler-bank-transfer.1 b/doc/taler-bank-transfer.1
index da13229b..2aab13fc 100644
--- a/doc/taler-bank-transfer.1
+++ b/doc/taler-bank-transfer.1
@@ -1,50 +1,55 @@
-.TH TALER\-BANK\-TRANSFER 1 "Dec 14, 2017" "GNU Taler"
-
-.SH NAME
-taler\-bank\-transfer \- Trigger a transfer at the bank
-
-.SH SYNOPSIS
-.B taler\-bank\-transfer
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-bank\-transfer\fP is a command line tool to trigger bank transfers.
-
-.SH OPTIONS
-.B
-.IP "\-a VALUE,  \-\-amount=VALUE"
-Amount to transfer.  Given in the Taler\-typical format of 
CURRENCY:VALUE.FRACTION
-.B
-.IP "\-b URL,  \-\-bank=URL"
+.Dd December 14, 2017
+.Dt TALER-BANK-TRANSFER 1
+.Os
+.Sh NAME
+.Nm taler-bank-transfer
+.Nd
+trigger a transfer at the bank
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar VALUE | Fl \-amount= Ns Ar VALUE
+.Op Fl b Ar URL | Fl \-bank= Ns Ar URL
+.Op Fl c Ar FILENAME | Fl \-config= Ns Ar FILENAME
+.Op Fl h | \-help
+.Op Fl D Ar ACCOUNT | Fl \-debit= Ns Ar ACCOUNT
+.Op Fl C Ar ACCOUNT | Fl \-credit= Ns Ar ACCOUNT
+.Op Fl s Ar STRING | Fl \-subject= Ns Ar STRING
+.Op Fl u Ar USERNAME | Fl \-user= Ns Ar USERNAME
+.Op Fl p Ar PASSPHRASE | Fl \-pass= Ns Ar PASSPHRASE
+.Op Fl v | \-version
+.Sh DESCRIPTION
+.Nm
+is a command line tool to trigger bank transfers.
+.Bl -tag -width Ds
+.It Fl a Ar VALUE | Fl \-amount= Ns Ar VALUE
+Amount to transfer.
+Given in the Taler\-typical format of CURRENCY:VALUE.FRACTION
+.It Fl b Ar URL | Fl \-bank= Ns Ar URL
 URL at which the bank is operation.
-.B
-.IP "\-c FILENAME,  \-\-config=FILENAME"
+.It Fl c Ar FILENAME | Fl \-config= Ns Ar FILENAME
 Use the given configuration file.
-.B
-.IP "\-h, \-\-help"
+.It Fl h | \-help
 Print short help on options.
-.B
-.IP "\-D ACCOUNT,  \-\-debit=ACCOUNT"
-The money should be debited from ACCOUNT.  Specifies the number of the account.
-.B
-.IP "\-C ACCOUNT,  \-\-credit=ACCOUNT"
-The money should be credited to ACCOUNT.  Specifies the number of the account.
-.B
-.IP "\-s STRING,  \-\-subject=STRING"
+.It Fl D Ar ACCOUNT | Fl \-debit= Ns Ar ACCOUNT
+The money should be debited from ACCOUNT.
+Specifies the number of the account.
+.It Fl C Ar ACCOUNT | Fl \-credit= Ns Ar ACCOUNT
+The money should be credited to ACCOUNT.
+Specifies the number of the account.
+.It Fl s Ar STRING | Fl \-subject= Ns Ar STRING
 Use STRING for the wire transfer subject.
-.B
-.IP "\-u USERNAME,  \-\-user=USERNAME"
+.It Fl u Ar USERNAME | Fl \-user= Ns Ar USERNAME
 Specifies the username for authentication.
-.B
-.IP "\-p PASSPHRASE,  \-\-pass=PASSPHRASE"
+.It Fl p Ar PASSPHRASE | Fl \-pass= Ns Ar PASSPHRASE
 Specifies the pass phrase for authentication.
-.B
-.IP "\-v, \-\-version"
+.It Fl v | \-version
 Print version information.
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
-
-.SH "SEE ALSO"
-\fBtaler\-bank\-manage\fP(1), \fBtaler.conf\fP(5)
+.El
+.Sh SEE ALSO
+.Xr taler-bank-manage 1 ,
+.Xr taler.conf 5
+.Sh BUGS
+Report bugs by using
+.Lk https://gnunet.org/bugs/
+or by sending electronic mail to
+.Aq Mt address@hidden
diff --git a/doc/taler-config-generate.1 b/doc/taler-config-generate.1
index 8a72cddd..2410fb38 100644
--- a/doc/taler-config-generate.1
+++ b/doc/taler-config-generate.1
@@ -1,63 +1,74 @@
-.TH TALER\-CONFIG\-GENERATE 1 "May 5, 2016" "GNU Taler"
-
-.SH NAME
-taler\-config\-generate \- tool to simplify Taler configuration generation
-
-.SH SYNOPSIS
-.B taler\-config\-generate
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-config\-generate\fP can be used to generate configuration files for 
the Taler exchange or Taler merchants
-
-.SH OPTIONS
-.B
-.IP "\-c FILENAME, \-\-config=FILENAME"
-Location where to write the generated configuration.  Existing file will be 
updated, not overwritten.
-.B
-.IP "\-C CURRENCY, \-\-currency=CURRENCY"
+.Dd May 5, 2016
+.Dt TALER-CONFIG-GENERATE 1
+.Os
+.Sh NAME
+.Nm taler-config-generate
+.Nd
+tool to simplify Taler configuration generation
+.Os
+.Sh SYNOPSIS
+.Nm
+.Op Fl c Ar FILENAME | Fl \-config= Ns Ar FILENAME
+.Op Fl C Ar CURRENCY | Fl \-currency= Ns Ar CURRENCY
+.Op Fl e | \-exchange
+.Op Fl f Ar AMOUNT | \-wirefee= Ns Ar AMOUNT
+.Op Fl m | \-merchant
+.Op Fl t | \-trusted
+.Op Fl w Ar WIREFORMAT | Fl \-wire Ar WIREFORMAT
+.Op Fl j Ar JSON | Fl \-wire-json-merchant= Ns Ar JSON
+.Op Fl J Ar JSON | Fl \-wire-json-exchange= Ns Ar JSON
+.Op Fl \-bank-uri
+.Op Fl \-exchange-bank-account
+.Op Fl \-merchant-bank-account
+.Op Fl h | \-help
+.Op Fl L Ar LOGLEVEL | Fl \-loglevel= Ns Ar LOGLEVEL
+.Op Fl v | \-version
+.Sh DESCRIPTION
+.Nm
+can be used to generate configuration files for the Taler exchange or Taler 
merchants.
+.Bl -tag -width Ds
+.It Fl c Ar FILENAME | Fl \-config= Ns Ar FILENAME
+Location where to write the generated configuration.
+Existing file will be updated, not overwritten.
+.It Fl C Ar CURRENCY | Fl \-currency= Ns Ar CURRENCY
 Which currency should we use in the configuration.
-.B
-.IP "\-e, \-\-exchange"
+.It Fl e | \-exchange
 Generate configuration for a Taler exchange.
-.B
-.IP "\-f AMOUNT, \-\-wirefee=AMOUNT"
+.It Fl f Ar AMOUNT | \-wirefee= Ns Ar AMOUNT
 Setup wire transfer fees for the next 5 years for the exchange (for all wire 
methods).
-.B
-.IP "\-m, \-\-merchant"
+.It Fl m | \-merchant
 Generate configuration for a Taler merchant.
-.B
-.IP "\-t, \-\-trusted"
-Setup current exchange as trusted with current merchant. Generally only useful 
when configuring for testcases.
-.B
-.IP "\-w WIREFORMAT, \-\-wire WIREFORMAT"
+.It Fl t | \-trusted
+Setup current exchange as trusted with current merchant.
+Generally only useful when configuring for testcases.
+.It Fl w Ar WIREFORMAT | Fl \-wire Ar WIREFORMAT
 Specifies which wire format to use (i.e. "test" or "sepa")
-.B
-.IP "\-j JSON, \-\-wire-json-merchant=JSON"
+.It Fl j Ar JSON | Fl \-wire-json-merchant= Ns Ar JSON
 Wire configuration to use for the merchant.
-.B
-.IP "\-J JSON, \-\-wire-json-exchange=JSON"
+.It Fl J Ar JSON | Fl \-wire-json-exchange= Ns Ar JSON
 Wire configuration to use for the exchange.
-.B
-.IP "\-\-bank-uri"
-Alternative to specify wire configuration to use for the exchange and merchant 
for the "test" wire method. Only useful if WIREFORMAT was set to "test".  
Specifies the URI of the bank.
-.B
-.IP "\-\-exchange-bank-account"
-Alternative to specify wire configuration to use for the exchange for the 
"test" wire method. Only useful if WIREFORMAT was set to "test".  Specifies the 
bank account number of the exchange.
-.B
-.IP "\-\-merchant-bank-account"
-Alternative to specify wire configuration to use for the merchant for the 
"test" wire method. Only useful if WIREFORMAT was set to "test". Specifies the 
bank account number of the merchant.
-.B
-.IP "\-h, \-\-help"
+.It Fl \-bank-uri
+Alternative to specify wire configuration to use for the exchange and merchant 
for the "test" wire method.
+Only useful if WIREFORMAT was set to "test".
+Specifies the URI of the bank.
+.It Fl \-exchange-bank-account
+Alternative to specify wire configuration to use for the exchange for the 
"test" wire method.
+Only useful if WIREFORMAT was set to "test".
+Specifies the bank account number of the exchange.
+.It Fl \-merchant-bank-account
+Alternative to specify wire configuration to use for the merchant for the 
"test" wire method.
+Only useful if WIREFORMAT was set to "test".
+Specifies the bank account number of the merchant.
+.It Fl h | \-help
 Shows this man page.
-.B
-.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL"
-Use LOGLEVEL for logging.  Valid values are DEBUG, INFO, WARNING and ERROR.
-.B
-.IP "\-v, \-\-version"
+.It Fl L Ar LOGLEVEL | Fl \-loglevel= Ns Ar LOGLEVEL
+Use LOGLEVEL for logging.
+Valid values are DEBUG, INFO, WARNING and ERROR.
+.It Fl v | \-version
 Print GNUnet version number.
-
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
+.El
+.Sh BUGS
+Report bugs by using
+.Lk https://gnunet.org/bugs/
+or by sending electronic mail to
+.Aq Mt address@hidden .
diff --git a/doc/taler-exchange-aggregator.1 b/doc/taler-exchange-aggregator.1
index 8525443e..48126214 100644
--- a/doc/taler-exchange-aggregator.1
+++ b/doc/taler-exchange-aggregator.1
@@ -1,32 +1,37 @@
-.TH TALER\-EXCHANGE\-AGGREGATOR 1 "Mar 30, 2016" "GNU Taler"
-
-.SH NAME
-taler\-exchange\-aggregator \- Aggregate and execute exchange transactions
-
-.SH SYNOPSIS
-.B taler\-exchange\-aggregator
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-exchange\-aggregator\fP is a command line tool to run pending 
transactions from the Taler exchange.
-
-.SH OPTIONS
-.B
-.IP "\-d DIRNAME,  \-\-exchange-dir=DIRNAME"
-Use the configuration and other resources for the exchange to operate from 
DIRNAME.
-.B
-.IP "\-h, \-\-help"
+.Dd Mar 30, 2016
+.Dt TALER-EXCHANGE-AGGREGATOR 1
+.Os
+.Sh NAME
+.Nm taler-exchange-aggregator
+.Nd
+Aggregate and execute exchange transactions
+.Sh SYNOPSIS
+.Nm
+.Op Fl d Ar DIRNAME | Fl \-exchange-dir= Ns Ar DIRNAME
+.Op Fl h | \-help
+.Op Fl t | \-test
+.Op Fl v | \-version
+.Sh DESCRIPTION
+.Nm
+is a command line tool to run pending transactions from the Taler exchange.
+.Bl -tag -width Ds
+.It Fl d Ar DIRNAME | Fl \-exchange-dir= Ns Ar DIRNAME
+Use the configuration and other resources for the exchange to operate from
+.Ar DIRNAME .
+.It Fl h | \-help
 Print short help on options.
-.B
-.IP "\-t,  \-\-test"
+.It Fl t | \-test
 Run in test mode and exit when idle.
-.B
-.IP "\-v, \-\-version"
+.It Fl v | \-version
 Print version information.
-.B
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
-
-.SH "SEE ALSO"
-\fBtaler\-exchange\-dbinit\fP(1), \fBtaler\-exchange\-keyup\fP(1), 
\fBtaler\-exchange\-httpd\fP(1), \fBtaler.conf\fP(5)
+.El
+.Sh SEE ALSO
+.Xr taler-exchange-dbinit 1 ,
+.Xr taler-exchange-keyup 1 ,
+.Xr taler-exchange-httpd 1 ,
+.Xr taler.conf 5 .
+.Sh BUGS
+Report bugs by using
+.Lk https://gnunet.org/bugs/
+or by sending electronic mail to
+.Aq Mt address@hidden .
diff --git a/doc/taler-exchange-benchmark.1 b/doc/taler-exchange-benchmark.1
index 11869375..fa099571 100644
--- a/doc/taler-exchange-benchmark.1
+++ b/doc/taler-exchange-benchmark.1
@@ -1,41 +1,44 @@
-.TH TALER\-EXCHANGE\-BENCHMARK 1 "Jul 25, 2018" "GNU Taler"
-
-.SH NAME
-taler\-exchange\-benchmark \- Measure exchange performance.
-
-.SH SYNOPSIS
-.B taler\-exchange\-benchmark
-.RI [ options ]
-.br
-
-.SH DESCRIPTION
-\fBtaler\-exchange\-benchmark\fP is a command line tool to measure the time 
spent to serve withdrawals/deposits/refreshes.  It usually needs a dedicate 
configuration file where all the services - the exchange and the (fake)bank - 
listen to URLs not subject to any reverse proxy, as say Nginx.  Moreover, the 
benchmark runs on a "volatile" database, that means that table are always 
erased during a single benchmark run.
-
-.SH OPTIONS
-
-.B
-.IP "\-c CONFIG_FILENAME,  \-\-config=CONFIG_FILENAME"
+.Dd July 25, 2018
+.Dt TALER-EXCHANGE-BENCHMARK 1
+.Os
+.Sh NAME
+.Nm taler-exchange-benchmark
+.Nd
+Measure exchange performance
+.Sh SYNOPSIS
+.Nm
+.Op Fl c Ar CONFIG_FILENAME | Fl \-config= Ns Ar CONFIG_FILENAME
+.Op Fl b Ar BANK_URL | Fl --bank-url= Ns Ar BANK_URL
+.Op Fl n Ar HOWMANY_COINS | Fl \-coins-number= Ns Ar HOWMANY_COINS
+.Op Fl l Ar LOGLEVEL | Fl \-log\-level= Ns Ar LOGLEVEL
+.Op Fl h | \-help
+.Sh DESCRIPTION
+.Nm
+is a command line tool to measure the time spent to serve 
withdrawals/deposits/refreshes.
+It usually needs a dedicate configuration file where all the services - the 
exchange and the (fake)bank - listen to URLs not subject to any reverse proxy, 
as say Nginx.
+Moreover, the benchmark runs on a "volatile" database, that means that table 
are always erased during a single benchmark run.
+.Bl -tag -width Ds
+.It Fl c Ar CONFIG_FILENAME | Fl \-config= Ns Ar CONFIG_FILENAME
 (Mandatory) Use CONFIG_FILENAME.
-
-.B
-.IP "\-b BANK_URL, --bank-url=BANK_URL"
-(Mandatory) The URL where the fakebank listens at.  Must match the host 
component in the exchange's escrow account "payto" URL.
-
-.B
-.IP "\-n HOWMANY_COINS, \-\-coins-number=HOWMANY_COINS"
-Defaults to 1.  Specifies how many coins this benchmark should withdraw and 
spend.  After being spent, each coin will be refreshed with a 
REFRESH_PROBABILITY probability, which is (hardcoded as) 0.1; future versions 
of this tool should offer this parameter as a CLI option.
-
-.B
-.IP "\-l LOGLEVEL, \-\-log\-level=LOGLEVEL"
+.It Fl b Ar BANK_URL | Fl --bank-url= Ns Ar BANK_URL
+(Mandatory) The URL where the fakebank listens at.
+Must match the host component in the exchange's escrow account "payto" URL.
+.It Fl n Ar HOWMANY_COINS | Fl \-coins-number= Ns Ar HOWMANY_COINS
+Defaults to 1.
+Specifies how many coins this benchmark should withdraw and spend.
+After being spent, each coin will be refreshed with a REFRESH_PROBABILITY 
probability, which is (hardcoded as) 0.1; future versions of this tool should 
offer this parameter as a CLI option.
+.It Fl l Ar LOGLEVEL | Fl \-log\-level= Ns Ar LOGLEVEL
 GNUnet-compatible log level, takes values "ERROR/WARNING/INFO/DEBUG"
-
-.B
-.IP "\-h, \-\-help"
+.It Fl h | \-help
 Prints a compiled-in help text.
-
-.B
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
-
-.SH "SEE ALSO"
-\fBtaler\-exchange\-dbinit\fP(1), \fBtaler\-exchange\-keyup\fP(1), 
\fBtaler\-exchange\-httpd\fP(1), \fBtaler.conf\fP(5)
+.El
+.Sh SEE ALSO
+.Xr taler-exchange-dbinit 1 ,
+.Xr taler-exchange-keyup 1 ,
+.Xr taler-exchange-httpd 1 ,
+.Xr taler.conf 5
+.Sh BUGS
+Report bugs by using
+.Lk https://gnunet.org/bugs/
+or by sending electronic mail to
+.Aq Mt address@hidden .
diff --git a/doc/taler-exchange.texi b/doc/taler-exchange.texi
index 4e6a0fb9..209e2dd5 100644
--- a/doc/taler-exchange.texi
+++ b/doc/taler-exchange.texi
@@ -239,37 +239,37 @@ Please install the following packages before proceeding 
with the exchange compil
 @itemize
 
 @item
-GNU autoconf @geq{} 2.69
+GNU autoconf >= 2.69
 
 @item
-GNU automake @geq{} 1.14
+GNU automake >= 1.14
 
 @item
-GNU libtool @geq{} 2.4
+GNU libtool >= 2.4
 
 @item
-GNU autopoint @geq{} 0.19
+GNU autopoint >= 0.19
 
 @item
-GNU libltdl @geq{} 2.4
+GNU libltdl >= 2.4
 
 @item
-GNU libunistring @geq{} 0.9.3
+GNU libunistring >= 0.9.3
 
 @item
-libcurl @geq{} 7.26 (or libgnurl @geq{} 7.26)
+libcurl >= 7.26 (or libgnurl >= 7.26)
 
 @item
-GNU libmicrohttpd @geq{} 0.9.59
+GNU libmicrohttpd >= 0.9.59
 
 @item
-GNU libgcrypt @geq{} 1.6
+GNU libgcrypt >= 1.6
 
 @item
-libjansson @geq{} 2.7
+libjansson >= 2.7
 
 @item
-Postgres @geq{} 9.6, including libpq
+Postgres >= 9.6, including libpq
 
 @item
 libgnunetutil (from Git)
@@ -292,7 +292,7 @@ to export some of the tooling required by Taler.
 To download and install libgnunetutil, proceed as follows:
 
 @example
-$ git clone https://gnunet.org/git/gnunet/
+$ git clone https://git.gnunet.org/gnunet/
 $ cd gnunet/
 $ ./bootstrap
 $ ./configure [--prefix=GNUNETPFX]
@@ -310,7 +310,7 @@ To download and install the GNU Taler exchange, proceeds as 
follows:
 
 @setsyntax shell
 @example
-$ git clone git://taler.net/exchange
+$ git clone git://git.taler.net/exchange
 $ cd exchange
 $ ./bootstrap
 $ ./configure [--prefix=EXCHANGEPFX] \
@@ -557,7 +557,7 @@ measure, may want to instruct the bank that the incoming 
bank account is only su
 
 For each wire method (``sepa'' or ``x-taler-wire'', but not per plugin!) the
 exchange configuration must specify applicable wire fees.  This is done
-in configuration sections of the format @code{fee-METHOD}.  There are two
+in configuration sections of the format @code{fees-METHOD}.  There are two
 types of fees, simple wire fees and closing fees.  Wire fees apply whenever
 the aggregator transfers funds to a merchant.  Closing fees apply whenever
 the exchange closes a reserve (sending back funds to the customer).  The
@@ -566,13 +566,13 @@ of the option.
 
 @setsyntax ini
 @example
-[fee-iban]
+[fees-iban]
 WIRE-FEE-2018 = EUR:0.01
 WIRE-FEE-2019 = EUR:0.01
 CLOSING-FEE-2018 = EUR:0.01
 CLOSING-FEE-2019 = EUR:0.01
 
-[fee-x-taler-bank]
+[fees-x-taler-bank]
 WIRE-FEE-2018 = KUDOS:0.01
 WIRE-FEE-2019 = KUDOS:0.01
 CLOSING-FEE-2018 = KUDOS:0.01
@@ -663,7 +663,7 @@ the two primes) have for this type of coin.
 
 
 Both @cite{signkeys} and @cite{denom keys} have a starting date. The
-option @cite{lookahead_provide}, under section @cite{[exchange_keys]},
+option @cite{lookahead_provide}, under section @cite{[exchange]},
 is such that only keys whose starting date is younger than
 @cite{lookahead_provide} will be issued by the exchange.
 
diff --git a/doc/taler.conf.5 b/doc/taler.conf.5
index 07d13f19..40e2d2d3 100644
--- a/doc/taler.conf.5
+++ b/doc/taler.conf.5
@@ -1,226 +1,248 @@
-.TH TALER.CONF 5 "Mar 20, 2018" "GNU Taler"
-
-.SH NAME
-taler.conf \- Taler configuration file.
-
-.SH SYNOPSIS
-.B taler.conf
-
-.SH DESCRIPTION
-
-The basic structure of the configuration file is the following.  The file is 
split into sections.  Every section begins with "[SECTIONNAME]" and contains a 
number of options of the form "OPTION=VALUE".  Empty lines and lines beginning 
with a "#" are treated as comments.  Files containing default values for many 
of the options described below are installed under 
$TALER\_PREFIX/share/taler/config.d/. The configuration file given with \-c to 
Taler binaries overrides these defaults.
-
-.SH GLOBAL OPTIONS
-
+.\" -*- mode: nroff -*-
+.Dd March 20, 2018
+.Dt TALER.CONF 5
+.Os
+.Sh NAME
+.Nm taler.conf
+.Nd
+Taler configuration file.
+.Sh DESCRIPTION
+The basic structure of the configuration file is the following.
+The file is split into sections.
+Every section begins with "[SECTIONNAME]" and contains a number of options of 
the form "OPTION=VALUE".
+Empty lines and lines beginning with a "#" are treated as comments.
+Files containing default values for many of the options described below are 
installed under $TALER\_PREFIX/share/taler/config.d/.
+The configuration file given with
+.Fl c
+to Taler binaries overrides these defaults.
+.Ss GLOBAL OPTIONS
 The following options are from the "[taler]" section and used by virtually all 
Taler components.
-
-.IP CURRENCY
-    Name of the currency, i.e. "EUR" for Euro.
-
-The "[PATHS]" section is special in that it contains paths that can be 
referenced using "$" in other configuration values that specify filenames.  For 
Taler, it commonly contains the following paths:
-
-.IP TALER_HOME
-    Home directory of the user, usually "${HOME}". Can be overwritten by 
testcases by setting ${TALER_TEST_HOME}.
-.IP TALER_DATA_HOME
-    Where should Taler store its long-term data.  Usually 
"${TALER_HOME}/.local/share/taler/"
-.IP TALER_CONFIG_HOME
-    Where is the Taler configuration kept.  Usually 
"${TALER_HOME}/.config/taler/"
-.IP TALER_CACHE_HOME
-    Where should Taler store cached data. Usually "${TALER_HOME}/.cache/taler/"
-.IP TALER_RUNTIME_DIR
-    Where should Taler store system runtime data (like UNIX domain sockets).  
Usually "${TMP}/taler-system-runtime".
-
-.SH EXCHANGE OPTIONS
-
-The following options are from the "[exchange]" section and used by most 
exchange tools:
-
-.IP DB
-    Plugin to use for the database, i.e. "postgres"
-.IP PORT
-    Port on which the HTTP server listens, i.e. 8080.
-.IP MASTER_PUBLIC_KEY
-    Crockford Base32-encoded master public key, public version of the 
exchange\'s long\-time offline signing key.
-.IP MASTER_PRIV_FILE
-    Location of the master private key on disk. Only used by tools that can be 
run offline (as the master key is for offline signing).
-.IP BASE_URL
-    Specifies the base URL under which the exchange can be reached. Added to 
wire transfers to enable tracking by merchants.
-.IP SIGNKEY_DURATION
-    For how long is a signing key valid?
-.IP LEGAL_DURATION
-    For how long are signatures with signing keys legally valid?
-.IP LOOKAHEAD_SIGN
-    How long do we generate denomination and signing keys ahead of time?
-.IP LOOKAHEAD_PROVIDE
-    How long into the future do we provide signing and denomination keys to 
clients?
-
-
-
-.SH EXCHANGE POSTGRES BACKEND DATABASE OPTIONS
-
-The following options must be in section "[exchangedb\-postgres]" if the 
"postgres" plugin was selected for the database:
-
-.IP CONFIG
-    How to access the database, i.e. "postgres:///taler" to use the "taler" 
database. Testcases use "talercheck".
-
-
-.SH MERCHANT OPTIONS
-
-The following options are from the "[merchant]" section and used by the 
merchant backend:
-
-.IP DB
-    Plugin to use for the database, i.e. "postgres"
-.IP PORT
-    Port on which the HTTP server listens, i.e. 8080.
-.IP WIRE_TRANSFER_DELAY
-    How quickly do we want the exchange to send us money? Note that wire 
transfer fees will be higher if we ask for money to be wired often.  Given as a 
relative time, i.e. "5 s"
-.IP DEFAULT_MAX_WIRE_FEE
-    Maximum wire fee we are willing to accept from exchanges.  Given as a 
Taler amount, i.e. "EUR:0.1"
-.IP DEFAULT_MAX_DEPOSIT_FEE
-    Maximum deposit fee we are willing to cover.  Given as a Taler amount, 
i.e. "EUR:0.1"
-
-
-.SH MERCHANT POSTGRES BACKEND DATABASE OPTIONS
-
-The following options must be in section "[merchantdb\-postgres]" if the 
"postgres" plugin was selected for the database:
-
-.IP CONFIG
-    How to access the database, i.e. "postgres:///taler" to use the "taler" 
database. Testcases use "talercheck".
-
-.SH MERCHANT INSTANCES
-
-The merchant configuration must specify a set of instances, containing at 
least the "default" instance.  The following options must be given in each 
"[instance-NAME]" section:
-
-.IP KEYFILE
-    Name of the file where the instance\'s private key is to be stored, i.e. 
"${TALER_CONFIG_HOME}/merchant/instance/name.priv"
-.IP NAME
-    Human-readable name of the instance, i.e. "Kudos Inc."
-
-Additionally, for instances that support tipping, the following options are 
required:
-
-.IP TIP_EXCHANGE
-    Base-URL of the exchange that holds the reserve for tipping, i.e. 
"https://exchange.demo.taler.net/";
-.IP TIP_EXCHANGE_PRIV_FILENAME
-    Filename with the private key granting access to the reserve, i.e. 
"${TALER_CONFIG_HOME}/merchant/reserve/tip.priv"
-
-
-.SH KNOWN EXCHANGES (for merchants and wallets)
-
-The merchant configuration can include a list of known exchanges if the 
merchant wants to specify that certain exchanges are explicitly trusted.  For 
each trusted exchange, a section [exchange-NAME] must exist, where NAME is a 
merchant-given name for the exchange.  The following options must be given in 
each "[exchange-NAME]" section:
-
-.IP BASE_URL
-    Base URL of the exchange, i.e. "https://exchange.demo.taler.net/";
-.IP MASTER_KEY
-    Crockford Base32 encoded master public key, public version of the 
exchange\'s long\-time offline signing key
-.IP CURRENCY
-    Name of the currency for which this exchange is trusted, i.e. "KUDOS"
-
-
-.SH KNOWN AUDITORS (for merchants and wallets)
-
-The merchant configuration can include a list of known exchanges if the 
merchant wants to specify that certain auditors are explicitly trusted.  For 
each trusted exchange, a section [auditor-NAME] must exist, where NAME is a 
merchant-given name for the exchange.  The following options must be given in 
each "[auditor-NAME]" section:
-
-.IP BASE_URL
-    Base URL of the auditor, i.e. "https://auditor.demo.taler.net/";
-.IP AUDITOR_KEY
-    Crockford Base32 encoded auditor public key.
-.IP CURRENCY
-    Name of the currency for which this auditor is trusted, i.e. "KUDOS"
-
-
-
-.SH ACCOUNT OPTIONS (for exchanges and merchants)
-
-An exchange (or merchant) can have multiple bank accounts. The following 
options are for sections named "[account-SOMETHING]".  The SOMETHING is 
arbitrary and should be chosen to uniquely identify the bank account for the 
operator.  Additional authentication options may need to be specified in the 
account section depending on the PLUGIN used.
-
-.IP URL
-    Specifies the payto://-URL of the account.  The general format is 
payto://METHOD/DETAILS.  This option is used for exchanges and merchants.
-.IP WIRE_RESPONSE
-    Specifies the name of the file in which the /wire response for this 
account should be located. Used by the Taler exchange service and the 
taler\-exchange\-wire tool and the taler\-merchant\-httpd (to generate the 
files).
-.IP PLUGIN
-    Name of the plugin can be used to access the account (i.e. "taler-bank" or 
"ebics"). Used by the merchant backend for back office operations (i.e. to 
identify incoming wire transfers) and by the exchange.
-.IP ENABLE_DEBIT
-    Must be set to YES for the accounts that the taler\-exchange\-aggregator 
should debit. Not used by merchants.
-.IP ENABLE_CREDIT
-    Must be set to YES for the accounts that the taler\-exchange\-wirewatch 
should check for credits. (It is yet uncertain if the merchant implementation 
may check this flag as well.)
-.IP HONOR_instance
-    Must be set to YES for the instances (where "instance" is the section name 
of the instance) of the merchant backend that should allow incoming wire 
transfers for this bank account.
-.IP ACTIVE_instance
-    Must be set to YES for the instances (where "instance" is the section name 
of the instance) of the merchant backend that should use this bank account in 
new offers/contracts.  Setting ACTIVE_instance to YES requires also setting 
ENABLE_instance to YES.
-
-
-.SH TALER-BANK AUTHENTICATION OPTIONS (for accounts)
-
-The following authentication options are supported by the "taler-bank" wire 
plugin. They must be specified in the "[account-]" section that uses the 
"taler-bank" plugin.
-
-.IP TALER_BANK_AUTH_METHOD
-    Authentication method to use. "none" or "basic" are currently supported.
-.IP USERNAME
-    Username to use for authentication. Used with the "basic" authentication 
method.
-.IP PASSWORD
-    Password to use for authentication. Used with the "basic" authentication 
method.
-
-.SH EBICS AUTHENTICATION OPTIONS
-
-The following authentication options are supported by the "ebics" wire plugin. 
They must be specified in the "[account-]" section that uses the "ebics" plugin.
-
-.IP NONE
-    Currently the "ebics" implementation is incomplete and does not support 
authentication.
-
-
-.SH EXCHANGE WIRE FEE OPTIONS
-
-For each supported wire method (i.e. "x-taler-bank" or "sepa"), sections named 
"[fees-METHOD]" state the (aggregate) wire transfer fee and the reserve closing 
fees charged by the exchange.  Note that fees are specified using the name of 
the wire method, not by the plugin name.  You need to replace "YEAR" in the 
option name by the calendar year for which the fee should apply.  Usually, fees 
should be given for serveral years in advance.
-
-.IP WIRE-FEE-YEAR
-    Aggregate wire transfer fee merchants are charged in YEAR.  Specified as a 
Taler amount using the usual amount syntax (CURRENCY:VALUE.FRACTION).
-.IP CLOSING-FEE-YEAR
-    Reserve closing fee customers are charged in YEAR.  Specified as a Taler 
amount using the usual amount syntax (CURRENCY:VALUE.FRACTION).
-
-
-.SH EXCHANGE COIN OPTIONS
-
-The following options must be in sections starting with "[coin_]" and are used 
by taler\-exchange\-keyup to create denomination keys:
-
-.IP VALUE
-    Value of the coin, i.e. "EUR:1.50" for 1 Euro and 50 Cents (per coin).
-.IP DURATION_OVERLAP
-    How much should validity periods for these coins overlap?
-.IP DURATION_WITHDRAW
-    How long should the same key be used for clients to withdraw coins of this 
value?
-.IP DURATION_SPEND
-    How long do clients have to spend these coins?
-.IP FEE_WITHDRAW
-    What fee is charged for withdrawl?
-.IP FEE_DEPOSIT
-    What fee is charged for depositing?
-.IP FEE_REFRESH
-    What fee is charged for refreshing?
-.IP FEE_REFUND
-    What fee is charged for refunds? When a coin is refunded, the deposit fee 
is returned. Instead, the refund fee is charged to the customer.
-.IP RSA_KEYSIZE
-    What is the RSA keysize modulos (in bits)?
-
-
-.SH AUDITOR OPTIONS
-
-The following options must be in section "[auditor]" for the Taler auditor:
-
-.IP DB
-    Plugin to use for the database, i.e. "postgres"
-.IP AUDITOR_PRIV_FILE
-    Name of the file containing the auditor's private key
-
-
-.SH AUDITOR POSTGRES BACKEND DATABASE OPTIONS
-
-The following options must be in section "[auditordb\-postgres]" if the 
"postgres" plugin was selected for the database:
-
-.IP CONFIG
-    How to access the database, i.e. "postgres:///taler" to use the "taler" 
database. Testcases use "talercheck".
-
-
-.SH BUGS
-Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending 
electronic mail to <address@hidden>
-
-.SH "SEE ALSO"
-\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), 
\fBtaler\-exchange\-dbinit\fP(1), \fBtaler\-exchange\-wire(1)
+.Bl -tag -width Ds
+.It CURRENCY
+Name of the currency, i.e. "EUR" for Euro.
+.El
+.Pp
+The "[PATHS]" section is special in that it contains paths that can be 
referenced using "$" in other configuration values that specify filenames.
+For Taler, it commonly contains the following paths:
+.Bl -tag -width Ds
+.It TALER_HOME
+Home directory of the user, usually "${HOME}".
+Can be overwritten by testcases by setting ${TALER_TEST_HOME}.
+.It TALER_DATA_HOME
+Where should Taler store its long-term data.  Usually 
"${TALER_HOME}/.local/share/taler/"
+.It TALER_CONFIG_HOME
+Where is the Taler configuration kept.
+Usually "${TALER_HOME}/.config/taler/"
+.It TALER_CACHE_HOME
+Where should Taler store cached data.
+Usually "${TALER_HOME}/.cache/taler/"
+.It TALER_RUNTIME_DIR
+Where should Taler store system runtime data (like UNIX domain sockets).
+Usually "${TMP}/taler-system-runtime".
+.El
+.Ss EXCHANGE OPTIONS
+The following options are from the "[exchange]" section and used by most 
exchange tools.
+.Bl -tag -width Ds
+.It DB
+Plugin to use for the database, i.e. "postgres"
+.It PORT
+Port on which the HTTP server listens, i.e. 8080.
+.It MASTER_PUBLIC_KEY
+Crockford Base32-encoded master public key, public version of the exchange\'s 
long\-time offline signing key.
+.It MASTER_PRIV_FILE
+Location of the master private key on disk.
+Only used by tools that can be run offline (as the master key is for offline 
signing).
+.It BASE_URL
+Specifies the base URL under which the exchange can be reached.
+Added to wire transfers to enable tracking by merchants.
+.It SIGNKEY_DURATION
+For how long is a signing key valid?
+.It LEGAL_DURATION
+For how long are signatures with signing keys legally valid?
+.It LOOKAHEAD_SIGN
+How long do we generate denomination and signing keys ahead of time?
+.It LOOKAHEAD_PROVIDE
+How long into the future do we provide signing and denomination keys to 
clients?
+.El
+.Ss EXCHANGE POSTGRES BACKEND DATABASE OPTIONS
+The following options must be in section "[exchangedb\-postgres]" if the 
"postgres" plugin was selected for the database.
+.Bl -tag -width Ds
+.It CONFIG
+How to access the database, i.e. "postgres:///taler" to use the "taler" 
database.
+Testcases use "talercheck".
+.El
+.Ss MERCHANT OPTIONS
+The following options are from the "[merchant]" section and used by the 
merchant backend.
+.Bl -tag -width Ds
+.It DB
+Plugin to use for the database, i.e. "postgres"
+.It PORT
+Port on which the HTTP server listens, i.e. 8080.
+.It WIRE_TRANSFER_DELAY
+How quickly do we want the exchange to send us money?
+Note that wire transfer fees will be higher if we ask for money to be wired 
often.
+Given as a relative time, i.e. "5 s"
+.It DEFAULT_MAX_WIRE_FEE
+Maximum wire fee we are willing to accept from exchanges.
+Given as a Taler amount, i.e. "EUR:0.1"
+.It DEFAULT_MAX_DEPOSIT_FEE
+Maximum deposit fee we are willing to cover.
+Given as a Taler amount, i.e. "EUR:0.1"
+.El
+.Ss MERCHANT POSTGRES BACKEND DATABASE OPTIONS
+The following options must be in section "[merchantdb\-postgres]" if the 
"postgres" plugin was selected for the database.
+.Bl -tag -width Ds
+.It CONFIG
+How to access the database, i.e. "postgres:///taler" to use the "taler" 
database.
+Testcases use "talercheck".
+.El
+.Ss MERCHANT INSTANCES
+The merchant configuration must specify a set of instances, containing at 
least the "default" instance.
+The following options must be given in each "[instance-NAME]" section.
+.Bl -tag -width Ds
+.It KEYFILE
+Name of the file where the instance\'s private key is to be stored, i.e. 
"${TALER_CONFIG_HOME}/merchant/instance/name.priv"
+.It NAME
+Human-readable name of the instance, i.e. "Kudos Inc."
+.El
+Additionally, for instances that support tipping, the following options are 
required.
+.Bl -tag -width Ds
+.It TIP_EXCHANGE
+Base-URL of the exchange that holds the reserve for tipping, i.e. 
"https://exchange.demo.taler.net/";
+.It TIP_EXCHANGE_PRIV_FILENAME
+Filename with the private key granting access to the reserve, i.e. 
"${TALER_CONFIG_HOME}/merchant/reserve/tip.priv"
+.El
+.Ss KNOWN EXCHANGES (for merchants and wallets)
+The merchant configuration can include a list of known exchanges if the 
merchant wants to specify that certain exchanges are explicitly trusted.
+For each trusted exchange, a section [exchange-NAME] must exist, where NAME is 
a merchant-given name for the exchange.
+The following options must be given in each "[exchange-NAME]" section.
+.Bl -tag -width Ds
+.It BASE_URL
+Base URL of the exchange, i.e. "https://exchange.demo.taler.net/";
+.It MASTER_KEY
+Crockford Base32 encoded master public key, public version of the exchange\'s 
long\-time offline signing key
+.It CURRENCY
+Name of the currency for which this exchange is trusted, i.e. "KUDOS"
+.El
+.Ss KNOWN AUDITORS (for merchants and wallets)
+The merchant configuration can include a list of known exchanges if the 
merchant wants to specify that certain auditors are explicitly trusted.
+For each trusted exchange, a section [auditor-NAME] must exist, where NAME is 
a merchant-given name for the exchange.
+The following options must be given in each "[auditor-NAME]" section.
+.Bl -tag -width Ds
+.It BASE_URL
+Base URL of the auditor, i.e. "https://auditor.demo.taler.net/";
+.It AUDITOR_KEY
+Crockford Base32 encoded auditor public key.
+.It CURRENCY
+Name of the currency for which this auditor is trusted, i.e. "KUDOS"
+.El
+.Ss ACCOUNT OPTIONS (for exchanges and merchants)
+An exchange (or merchant) can have multiple bank accounts.
+The following options are for sections named "[account-SOMETHING]".
+The SOMETHING is arbitrary and should be chosen to uniquely identify the bank 
account for the operator.
+Additional authentication options may need to be specified in the account 
section depending on the PLUGIN used.
+.Bl -tag -width Ds
+.It URL
+Specifies the payto://-URL of the account.
+The general format is payto://METHOD/DETAILS.
+This option is used for exchanges and merchants.
+.It WIRE_RESPONSE
+Specifies the name of the file in which the /wire response for this account 
should be located.
+Used by the Taler exchange service and the taler\-exchange\-wire tool and the 
taler\-merchant\-httpd (to generate the files).
+.It PLUGIN
+Name of the plugin can be used to access the account (i.e. "taler-bank" or 
"ebics").
+Used by the merchant backend for back office operations (i.e. to identify 
incoming wire transfers) and by the exchange.
+.It ENABLE_DEBIT
+Must be set to YES for the accounts that the taler\-exchange\-aggregator 
should debit.
+Not used by merchants.
+.It ENABLE_CREDIT
+Must be set to YES for the accounts that the taler\-exchange\-wirewatch should 
check for credits.
+It is yet uncertain if the merchant implementation may check this flag as well.
+.It HONOR_instance
+Must be set to YES for the instances (where "instance" is the section name of 
the instance) of the merchant backend that should allow incoming wire transfers 
for this bank account.
+.It ACTIVE_instance
+Must be set to YES for the instances (where "instance" is the section name of 
the instance) of the merchant backend that should use this bank account in new 
offers/contracts.
+Setting ACTIVE_instance to YES requires also setting ENABLE_instance to YES.
+.El
+.Ss TALER-BANK AUTHENTICATION OPTIONS (for accounts)
+The following authentication options are supported by the "taler-bank" wire 
plugin.
+They must be specified in the "[account-]" section that uses the "taler-bank" 
plugin.
+.Bl -tag -width Ds
+.It TALER_BANK_AUTH_METHOD
+Authentication method to use.
+"none" or "basic" are currently supported.
+.It USERNAME
+Username to use for authentication.
+Used with the "basic" authentication method.
+.It PASSWORD
+Password to use for authentication.
+Used with the "basic" authentication method.
+.Ss EBICS AUTHENTICATION OPTIONS
+The following authentication options are supported by the "ebics" wire plugin.
+They must be specified in the "[account-]" section that uses the "ebics" 
plugin.
+.Bl -tag -width Ds
+.It NONE
+Currently the "ebics" implementation is incomplete and does not support 
authentication.
+.El
+.Ss EXCHANGE WIRE FEE OPTIONS
+For each supported wire method (i.e. "x-taler-bank" or "sepa"), sections named 
"[fees-METHOD]" state the (aggregate) wire transfer fee and the reserve closing 
fees charged by the exchange.
+Note that fees are specified using the name of the wire method, not by the 
plugin name.
+You need to replace "YEAR" in the option name by the calendar year for which 
the fee should apply.
+Usually, fees should be given for serveral years in advance.
+.Bl -tag -width Ds
+.It WIRE-FEE-YEAR
+Aggregate wire transfer fee merchants are charged in YEAR.
+Specified as a Taler amount using the usual amount syntax 
(CURRENCY:VALUE.FRACTION).
+.It CLOSING-FEE-YEAR
+Reserve closing fee customers are charged in YEAR.
+Specified as a Taler amount using the usual amount syntax 
(CURRENCY:VALUE.FRACTION).
+.El
+.Ss EXCHANGE COIN OPTIONS
+The following options must be in sections starting with "[coin_]" and are used 
by taler\-exchange\-keyup to create denomination keys.
+.Bl -tag -width Ds
+.It VALUE
+Value of the coin, i.e. "EUR:1.50" for 1 Euro and 50 Cents (per coin).
+.It DURATION_OVERLAP
+How much should validity periods for these coins overlap?
+.It DURATION_WITHDRAW
+How long should the same key be used for clients to withdraw coins of this 
value?
+.It DURATION_SPEND
+How long do clients have to spend these coins?
+.It FEE_WITHDRAW
+What fee is charged for withdrawl?
+.It FEE_DEPOSIT
+What fee is charged for depositing?
+.It FEE_REFRESH
+What fee is charged for refreshing?
+.It FEE_REFUND
+What fee is charged for refunds?
+When a coin is refunded, the deposit fee is returned.
+Instead, the refund fee is charged to the customer.
+.It RSA_KEYSIZE
+What is the RSA keysize modulos (in bits)?
+.El
+.Ss AUDITOR OPTIONS
+The following options must be in section "[auditor]" for the Taler auditor.
+.Bl -tag -width Ds
+.It DB
+Plugin to use for the database, i.e. "postgres"
+.It AUDITOR_PRIV_FILE
+Name of the file containing the auditor's private key
+.El
+.Ss AUDITOR POSTGRES BACKEND DATABASE OPTIONS
+The following options must be in section "[auditordb\-postgres]" if the 
"postgres" plugin was selected for the database.
+.Bl -tag -width Ds
+.It CONFIG
+How to access the database, i.e. "postgres:///taler" to use the "taler" 
database.
+Testcases use "talercheck".
+.El
+.Sh SEE ALSO
+.Xr taler-exchange-dbinit 1 ,
+.Xr taler-exchange-httpd 1 ,
+.Xr taler-exchange-keyup 1 ,
+.Xr taler-exchange-wire 1 .
+.Sh BUGS
+Report bugs by using
+.Lk https://gnunet.org/bugs/
+or by sending electronic mail to
+.Aq Mt address@hidden .
diff --git a/src/auditor/taler-auditor-httpd_parsing.c 
b/src/auditor/taler-auditor-httpd_parsing.c
index ebbe50ee..6c4bece9 100644
--- a/src/auditor/taler-auditor-httpd_parsing.c
+++ b/src/auditor/taler-auditor-httpd_parsing.c
@@ -70,6 +70,7 @@ TAH_PARSE_post_json (struct MHD_Connection *connection,
   enum GNUNET_JSON_PostResult pr;
 
   pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+                                connection,
                                 con_cls,
                                 upload_data,
                                 upload_data_size,
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index 1b9c99c8..0cd84523 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -562,25 +562,18 @@ static struct GNUNET_CONTAINER_MultiHashMap 
*denominations;
 /**
  * Obtain information about a @a denom_pub.
  *
- * @param denom_pub key to look up
+ * @param dh hash of the denomination public key to look up
  * @param[out] dki set to detailed information about @a denom_pub, NULL if not 
found, must
  *                 NOT be freed by caller
- * @param[out] dh set to the hash of @a denom_pub, may be NULL
  * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
-get_denomination_info (const struct TALER_DenominationPublicKey *denom_pub,
-                       const struct 
TALER_EXCHANGEDB_DenominationKeyInformationP **dki,
-                       struct GNUNET_HashCode *dh)
+get_denomination_info_by_hash (const struct GNUNET_HashCode *dh,
+                       const struct 
TALER_EXCHANGEDB_DenominationKeyInformationP **dki)
 {
-  struct GNUNET_HashCode hc;
   struct TALER_EXCHANGEDB_DenominationKeyInformationP *dkip;
   enum GNUNET_DB_QueryStatus qs;
 
-  if (NULL == dh)
-    dh = &hc;
-  GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
-                                     dh);
   if (NULL == denominations)
     denominations = GNUNET_CONTAINER_multihashmap_create (256,
                                                           GNUNET_NO);
@@ -594,9 +587,9 @@ get_denomination_info (const struct 
TALER_DenominationPublicKey *denom_pub,
   }
   dkip = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyInformationP);
   qs = edb->get_denomination_info (edb->cls,
-                                  esession,
-                                  denom_pub,
-                                  dkip);
+                                   esession,
+                                   dh,
+                                   dkip);
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   {
     GNUNET_free (dkip);
@@ -624,6 +617,31 @@ get_denomination_info (const struct 
TALER_DenominationPublicKey *denom_pub,
 
 
 /**
+ * Obtain information about a @a denom_pub.
+ *
+ * @param denom_pub key to look up
+ * @param[out] dki set to detailed information about @a denom_pub, NULL if not 
found, must
+ *                 NOT be freed by caller
+ * @param[out] dh set to the hash of @a denom_pub, may be NULL
+ * @return transaction status code
+ */
+static enum GNUNET_DB_QueryStatus
+get_denomination_info (const struct TALER_DenominationPublicKey *denom_pub,
+                       const struct 
TALER_EXCHANGEDB_DenominationKeyInformationP **dki,
+                       struct GNUNET_HashCode *dh)
+{
+  struct GNUNET_HashCode hc;
+
+  if (NULL == dh)
+    dh = &hc;
+  GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
+                                     dh);
+  return get_denomination_info_by_hash (dh,
+                                        dki);
+}
+
+
+/**
  * Free denomination key information.
  *
  * @param cls NULL
@@ -1065,6 +1083,7 @@ handle_payback_by_reserve (void *cls,
                            const struct TALER_Amount *amount,
                            const struct TALER_ReservePublicKeyP *reserve_pub,
                            const struct TALER_CoinPublicInfo *coin,
+                           const struct TALER_DenominationPublicKey *denom_pub,
                            const struct TALER_CoinSpendSignatureP *coin_sig,
                            const struct TALER_DenominationBlindingKeyP 
*coin_blind)
 {
@@ -1081,11 +1100,12 @@ handle_payback_by_reserve (void *cls,
   /* should be monotonically increasing */
   GNUNET_assert (rowid >= ppr.last_reserve_payback_serial_id);
   ppr.last_reserve_payback_serial_id = rowid + 1;
-  GNUNET_CRYPTO_rsa_public_key_hash (coin->denom_pub.rsa_public_key,
-                                     &pr.h_denom_pub);
+  // FIXME: should probably check that denom_pub hashes to this hash code!
+  pr.h_denom_pub = coin->denom_pub_hash;
 
   if (GNUNET_OK !=
-      TALER_test_coin_valid (coin))
+      TALER_test_coin_valid (coin,
+                             denom_pub))
   {
     report (report_bad_sig_losses,
             json_pack ("{s:s, s:I, s:o, s:o}",
@@ -1975,12 +1995,10 @@ check_transaction_history (const struct 
TALER_CoinSpendPublicKeyP *coin_pub,
       }
       /* Check if this deposit is within the remit of the aggregation
          we are investigating, if so, include it in the totals. */
-      if ( (0 == memcmp (merchant_pub,
-                         &tl->details.deposit->merchant_pub,
-                         sizeof (struct TALER_MerchantPublicKeyP))) &&
-           (0 == memcmp (h_contract_terms,
-                         &tl->details.deposit->h_contract_terms,
-                         sizeof (struct GNUNET_HashCode))) )
+      if ( (0 == GNUNET_memcmp (merchant_pub,
+                                &tl->details.deposit->merchant_pub)) &&
+           (0 == GNUNET_memcmp (h_contract_terms,
+                                &tl->details.deposit->h_contract_terms)) )
       {
         struct TALER_Amount amount_without_fee;
 
@@ -2063,12 +2081,10 @@ check_transaction_history (const struct 
TALER_CoinSpendPublicKeyP *coin_pub,
       }
       /* Check if this refund is within the remit of the aggregation
          we are investigating, if so, include it in the totals. */
-      if ( (0 == memcmp (merchant_pub,
-                         &tl->details.refund->merchant_pub,
-                         sizeof (struct TALER_MerchantPublicKeyP))) &&
-           (0 == memcmp (h_contract_terms,
-                         &tl->details.refund->h_contract_terms,
-                         sizeof (struct GNUNET_HashCode))) )
+      if ( (0 == GNUNET_memcmp (merchant_pub,
+                                &tl->details.refund->merchant_pub)) &&
+           (0 == GNUNET_memcmp (h_contract_terms,
+                                &tl->details.refund->h_contract_terms)) )
       {
         if (GNUNET_OK !=
             TALER_amount_add (&merchant_loss,
@@ -2223,9 +2239,8 @@ wire_transfer_information_cb (void *cls,
     return;
   }
   if (0 !=
-      memcmp (&hw,
-              h_wire,
-              sizeof (struct GNUNET_HashCode)))
+      GNUNET_memcmp (&hw,
+                     h_wire))
   {
     wcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
     report_row_inconsistency ("aggregation",
@@ -2268,9 +2283,8 @@ wire_transfer_information_cb (void *cls,
     break;
   }
   GNUNET_assert (NULL != coin); /* hard check that switch worked */
-  qs = get_denomination_info (&coin->denom_pub,
-                             &dki,
-                             NULL);
+  qs = get_denomination_info_by_hash (&coin->denom_pub_hash,
+                                      &dki);
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   {
     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
@@ -2320,18 +2334,16 @@ wire_transfer_information_cb (void *cls,
                                    tl);
 
   /* Check other details of wire transfer match */
-  if (0 != memcmp (h_wire,
-                   &wcc->h_wire,
-                   sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (h_wire,
+                          &wcc->h_wire))
   {
     wcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
     report_row_inconsistency ("aggregation",
                               rowid,
                               "wire method of aggregate do not match wire 
transfer");
   }
-  if (0 != memcmp (h_wire,
-                   &wcc->h_wire,
-                   sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (h_wire,
+                          &wcc->h_wire))
   {
     wcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
     report_row_inconsistency ("aggregation",
@@ -4393,9 +4405,8 @@ test_master_present (void *cls,
   int *found = cls;
 
   (void) exchange_url;
-  if (0 == memcmp (mpub,
-                  &master_pub,
-                  sizeof (master_pub)))
+  if (0 == GNUNET_memcmp (mpub,
+                          &master_pub))
     *found = GNUNET_YES;
 }
 
@@ -4423,9 +4434,8 @@ run (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Launching auditor\n");
   cfg = c;
-  if (0 == memcmp (&zeromp,
-                   &master_pub,
-                   sizeof (struct TALER_MasterPublicKeyP)))
+  if (0 == GNUNET_memcmp (&zeromp,
+                          &master_pub))
   {
     /* -m option not given, try configuration */
     char *master_public_key_str;
diff --git a/src/auditor/taler-wire-auditor.c b/src/auditor/taler-wire-auditor.c
index c903a494..7b96e34e 100644
--- a/src/auditor/taler-wire-auditor.c
+++ b/src/auditor/taler-wire-auditor.c
@@ -1244,9 +1244,8 @@ history_credit_cb (void *cls,
                        "diagnostic", "wire reference size missmatch"));
     return GNUNET_OK;
   }
-  if (0 != memcmp (&details->wtid,
-                  &rii->details.wtid,
-                  sizeof (struct TALER_WireTransferIdentifierRawP)))
+  if (0 != GNUNET_memcmp (&details->wtid,
+                          &rii->details.wtid))
   {
     report (report_reserve_in_inconsistencies,
             json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
@@ -1536,9 +1535,8 @@ run (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Launching auditor\n");
   cfg = c;
-  if (0 == memcmp (&zeromp,
-                   &master_pub,
-                   sizeof (struct TALER_MasterPublicKeyP)))
+  if (0 == GNUNET_memcmp (&zeromp,
+                          &master_pub))
   {
     /* -m option not given, try configuration */
     char *master_public_key_str;
diff --git a/src/auditordb/test_auditordb.c b/src/auditordb/test_auditordb.c
index f4289290..19104375 100644
--- a/src/auditordb/test_auditordb.c
+++ b/src/auditordb/test_auditordb.c
@@ -70,9 +70,8 @@ select_denomination_info_result (void *cls,
 {
   const struct TALER_DenominationKeyValidityPS *issue1 = cls;
 
-  if (0 != memcmp (issue1,
-                  issue2,
-                  sizeof (*issue2)))
+  if (0 != GNUNET_memcmp (issue1,
+                          issue2))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "select_denomination_info_result: issue does not match\n");
@@ -317,9 +316,9 @@ run (void *cls)
                                     &withdraw_fee_balance2,
                                     &date));
 
-  FAILIF (0 != memcmp (&date, &future, sizeof (future))
-          || 0 != memcmp (&reserve_balance2, &reserve_balance, sizeof 
(reserve_balance))
-          || 0 != memcmp (&withdraw_fee_balance2, &withdraw_fee_balance, 
sizeof (withdraw_fee_balance)));
+  FAILIF (0 != GNUNET_memcmp (&date, &future)
+          || 0 != GNUNET_memcmp (&reserve_balance2, &reserve_balance)
+          || 0 != GNUNET_memcmp (&withdraw_fee_balance2, 
&withdraw_fee_balance));
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Test: insert_reserve_summary\n");
@@ -354,12 +353,10 @@ run (void *cls)
                                        &reserve_balance2,
                                        &withdraw_fee_balance2));
 
-  FAILIF ( (0 != memcmp (&reserve_balance2,
-                        &reserve_balance,
-                        sizeof (reserve_balance)) ||
-           (0 != memcmp (&withdraw_fee_balance2,
-                         &withdraw_fee_balance,
-                         sizeof (withdraw_fee_balance))) ) );
+  FAILIF ( (0 != GNUNET_memcmp (&reserve_balance2,
+                                &reserve_balance) ||
+           (0 != GNUNET_memcmp (&withdraw_fee_balance2,
+                             &withdraw_fee_balance)) ) );
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Test: insert_denomination_balance\n");
@@ -426,8 +423,8 @@ run (void *cls)
                                             &rbalance2,
                                             &nissued));
 
-  FAILIF (0 != memcmp (&denom_balance2, &denom_balance, sizeof 
(denom_balance)));
-  FAILIF (0 != memcmp (&rbalance2, &rbalance, sizeof (rbalance)));
+  FAILIF (0 != GNUNET_memcmp (&denom_balance2, &denom_balance));
+  FAILIF (0 != GNUNET_memcmp (&rbalance2, &rbalance));
   FAILIF (62 != nissued);
 
 
@@ -476,21 +473,16 @@ run (void *cls)
                                             &refund_fee_balance2,
                                             &rbalance2));
 
-  FAILIF ( (0 != memcmp (&denom_balance2,
-                        &denom_balance,
-                        sizeof (denom_balance)) ) ||
-          (0 != memcmp (&deposit_fee_balance2,
-                        &deposit_fee_balance,
-                        sizeof (deposit_fee_balance)) ) ||
-          (0 != memcmp (&melt_fee_balance2,
-                        &melt_fee_balance,
-                        sizeof (melt_fee_balance)) ) ||
-          (0 != memcmp (&refund_fee_balance2,
-                        &refund_fee_balance,
-                        sizeof (refund_fee_balance))) );
-  FAILIF (0 != memcmp (&rbalance2,
-                      &rbalance,
-                      sizeof (rbalance)));
+  FAILIF ( (0 != GNUNET_memcmp (&denom_balance2,
+                                &denom_balance) ) ||
+          (0 != GNUNET_memcmp (&deposit_fee_balance2,
+                            &deposit_fee_balance) ) ||
+          (0 != GNUNET_memcmp (&melt_fee_balance2,
+                            &melt_fee_balance) ) ||
+          (0 != GNUNET_memcmp (&refund_fee_balance2,
+                            &refund_fee_balance)) );
+  FAILIF (0 != GNUNET_memcmp (&rbalance2,
+                              &rbalance));
 
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -528,11 +520,11 @@ run (void *cls)
 
     if (2 <= n++
         || cls != NULL
-        || (0 != memcmp (&revenue_timestamp2, &past, sizeof (past))
-            && 0 != memcmp (&revenue_timestamp2, &now, sizeof (now)))
-        || (0 != memcmp (denom_pub_hash2, &denom_pub_hash, sizeof 
(denom_pub_hash))
-            && 0 != memcmp (denom_pub_hash2, &rnd_hash, sizeof (rnd_hash)))
-        || 0 != memcmp (revenue_balance2, &rbalance, sizeof (rbalance)))
+        || (0 != GNUNET_memcmp (&revenue_timestamp2, &past)
+            && 0 != GNUNET_memcmp (&revenue_timestamp2, &now))
+        || (0 != GNUNET_memcmp (denom_pub_hash2, &denom_pub_hash)
+            && 0 != GNUNET_memcmp (denom_pub_hash2, &rnd_hash))
+        || 0 != GNUNET_memcmp (revenue_balance2, &rbalance))
     {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "select_historic_denom_revenue_result: result does not 
match\n");
@@ -585,11 +577,11 @@ run (void *cls)
 
     if (2 <= n++
         || cls != NULL
-        || (0 != memcmp (&loss_timestamp2, &past, sizeof (past))
-            && 0 != memcmp (&loss_timestamp2, &now, sizeof (now)))
-        || (0 != memcmp (denom_pub_hash2, &denom_pub_hash, sizeof 
(denom_pub_hash))
-            && 0 != memcmp (denom_pub_hash2, &rnd_hash, sizeof (rnd_hash)))
-        || 0 != memcmp (loss_balance2, &rbalance, sizeof (rbalance)))
+        || (0 != GNUNET_memcmp (&loss_timestamp2, &past)
+            && 0 != GNUNET_memcmp (&loss_timestamp2, &now))
+        || (0 != GNUNET_memcmp (denom_pub_hash2, &denom_pub_hash)
+            && 0 != GNUNET_memcmp (denom_pub_hash2, &rnd_hash))
+        || 0 != GNUNET_memcmp (loss_balance2, &rbalance))
     {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "select_historic_denom_revenue_result: result does not 
match\n");
@@ -646,10 +638,10 @@ run (void *cls)
 
     if (2 <= n++
         || cls != NULL
-        || (0 != memcmp (&start_time2, &past, sizeof (past))
-            && 0 != memcmp (&start_time2, &now, sizeof (now)))
-        || 0 != memcmp (&end_time2, &future, sizeof (future))
-        || 0 != memcmp (reserve_profits2, &reserve_profits, sizeof 
(reserve_profits)))
+        || (0 != GNUNET_memcmp (&start_time2, &past)
+            && 0 != GNUNET_memcmp (&start_time2, &now))
+        || 0 != GNUNET_memcmp (&end_time2, &future)
+        || 0 != GNUNET_memcmp (reserve_profits2, &reserve_profits))
     {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "select_historic_reserve_revenue_result: result does not 
match\n");
diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am
index e6e2e878..0858efb3 100644
--- a/src/bank-lib/Makefile.am
+++ b/src/bank-lib/Makefile.am
@@ -6,7 +6,7 @@ if USE_COVERAGE
   XLIB = -lgcov
 endif
 
-noinst_PROGRAMS = \
+bin_PROGRAMS = \
   taler-bank-transfer
 
 noinst_PROGRAMS = \
@@ -57,6 +57,7 @@ libtalerfakebank_la_LDFLAGS = \
   -no-undefined
 
 libtalerfakebank_la_SOURCES = \
+  fakebank_history.c \
   fakebank.c
 
 libtalerfakebank_la_LIBADD = \
diff --git a/src/bank-lib/bank_api_admin.c b/src/bank-lib/bank_api_admin.c
index 3a1ec4ef..8eff229f 100644
--- a/src/bank-lib/bank_api_admin.c
+++ b/src/bank-lib/bank_api_admin.c
@@ -79,6 +79,7 @@ handle_admin_add_incoming_finished (void *cls,
 {
   struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
   uint64_t row_id = UINT64_MAX;
+  struct GNUNET_TIME_Absolute timestamp;
   enum TALER_ErrorCode ec;
   const json_t *j = response;
 
@@ -93,6 +94,8 @@ handle_admin_add_incoming_finished (void *cls,
       struct GNUNET_JSON_Specification spec[] = {
         GNUNET_JSON_spec_uint64 ("row_id",
                                  &row_id),
+        GNUNET_JSON_spec_absolute_time ("timestamp",
+                                        &timestamp),
         GNUNET_JSON_spec_end()
       };
 
@@ -148,6 +151,7 @@ handle_admin_add_incoming_finished (void *cls,
            response_code,
            ec,
            row_id,
+           timestamp,
            j);
   TALER_BANK_admin_add_incoming_cancel (aai);
 }
diff --git a/src/bank-lib/bank_api_history.c b/src/bank-lib/bank_api_history.c
index ab757a2d..5cdac917 100644
--- a/src/bank-lib/bank_api_history.c
+++ b/src/bank-lib/bank_api_history.c
@@ -2,22 +2,26 @@
   This file is part of TALER
   Copyright (C) 2017 GNUnet e.V. & Inria
 
-  TALER is free software; you can redistribute it and/or modify it under the
-  terms of the GNU General Public License as published by the Free Software
-  Foundation; either version 3, or (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with
-  TALER; see the file COPYING.  If not, see
-  <http://www.gnu.org/licenses/>
+  TALER is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 3,
+  or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not,
+  see <http://www.gnu.org/licenses/>
 */
 /**
  * @file bank-lib/bank_api_history.c
- * @brief Implementation of the /history requests of the bank's HTTP API
+ * @brief Implementation of the /history[-range]
+ *        requests of the bank's HTTP API.
  * @author Christian Grothoff
+ * @author Marcello Stanisci
  */
 #include "platform.h"
 #include "bank_api_common.h"
@@ -60,7 +64,23 @@ struct TALER_BANK_HistoryHandle
    * Closure for @a cb.
    */
   void *hcb_cls;
+};
+
+
+/**
+ * Represent a URL argument+value pair.
+ */
+struct HistoryArgumentURL
+{
+  /**
+   * Name of the URL argument.
+   */
+  char argument[20];
 
+  /**
+   * Value of the URL argument.
+   */
+  char value[20];
 };
 
 
@@ -248,24 +268,202 @@ handle_history_finished (void *cls,
 }
 
 
+
+/**
+ * Backend of both the /history[-range] requests.
+ *
+ * @param ctx curl context for the event loop
+ * @param bank_base_url base URL of the bank.
+ * @param urlargs path + URL arguments.
+ * @param auth authentication data to use
+ * @param hres_cb the callback to call with the transaction
+ *        history
+ * @param hres_cb_cls closure for the above callback
+ * @return NULL if the inputs are invalid (i.e. zero value for
+ *         @e num_results). In this case, the callback is not
+ *         called.
+ */
+static struct TALER_BANK_HistoryHandle *
+put_history_job (struct GNUNET_CURL_Context *ctx,
+                 const char *bank_base_url,
+                 const char *urlargs,
+                 const struct TALER_BANK_AuthenticationData *auth,
+                 TALER_BANK_HistoryResultCallback hres_cb,
+                 void *hres_cb_cls)
+{
+  struct TALER_BANK_HistoryHandle *hh;
+  CURL *eh;
+
+  hh = GNUNET_new (struct TALER_BANK_HistoryHandle);
+  hh->hcb = hres_cb;
+  hh->hcb_cls = hres_cb_cls;
+  hh->bank_base_url = GNUNET_strdup (bank_base_url);
+  hh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
+                                             urlargs);
+
+  hh->authh = TALER_BANK_make_auth_header_ (auth);
+  eh = curl_easy_init ();
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_HTTPHEADER,
+                                   hh->authh));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_URL,
+                                   hh->request_url));
+  hh->job = GNUNET_CURL_job_add (ctx,
+                                 eh,
+                                 GNUNET_NO,
+                                 &handle_history_finished,
+                                 hh);
+  return hh;
+}
+
+
+/**
+ * Convert fixed value 'direction' into string.
+ *
+ * @param direction the value to convert.
+ * @return string representation of @a direction.  When length
+ *         is zero, an error occurred.
+ */
+static struct HistoryArgumentURL
+conv_direction (enum TALER_BANK_Direction direction)
+{
+  struct HistoryArgumentURL ret;
+
+  if (TALER_BANK_DIRECTION_NONE == direction)
+  {
+    /* Should just never happen.  */
+    GNUNET_assert (0);
+    return ret;
+  }
+
+  if (TALER_BANK_DIRECTION_BOTH ==
+      (TALER_BANK_DIRECTION_BOTH & direction))
+    strcpy (&ret.value[0],
+            "both");
+  else if (TALER_BANK_DIRECTION_CREDIT ==
+      (TALER_BANK_DIRECTION_CREDIT & direction))
+    strcpy (&ret.value[0],
+            "credit");
+  else if (TALER_BANK_DIRECTION_DEBIT ==
+      (TALER_BANK_DIRECTION_BOTH & direction)) /*why use 'both' flag?*/
+    strcpy (&ret.value[0],
+            "debit");
+  return ret;
+}
+
+
+/**
+ * Convert fixed value 'direction' into string representation
+ * of the "cancel" argument.
+ *
+ * @param direction the value to convert.
+ * @return string representation of @a direction.  When length
+ *         is zero, an error occurred.
+ */
+static struct HistoryArgumentURL
+conv_cancel (enum TALER_BANK_Direction direction)
+{
+  struct HistoryArgumentURL ret;
+
+  if (TALER_BANK_DIRECTION_CANCEL ==
+      (TALER_BANK_DIRECTION_CANCEL & direction))
+    strcpy (&ret.value[0],
+            "show");
+  else
+    strcpy (&ret.value[0],
+            "omit");
+  return ret;
+}
+
+/**
+ * Request the wire transfer history of a bank account,
+ * using time stamps to narrow the results.
+ *
+ * @param ctx curl context for the event loop
+ * @param bank_base_url URL of the bank (used to execute this
+ *        request)
+ * @param auth authentication data to use
+ * @param account_number which account number should we query
+ * @param direction what kinds of wire transfers should be
+ *        returned
+ * @param ascending if GNUNET_YES, history elements will
+ *        be returned in chronological order.
+ * @param start_date threshold for oldest result.
+ * @param end_date threshold for youngest result.
+ * @param hres_cb the callback to call with the transaction
+ *        history
+ * @param hres_cb_cls closure for the above callback
+ * @return NULL if the inputs are invalid (i.e. zero value for
+ *         @e num_results). In this case, the callback is not
+ *         called.
+ */
+struct TALER_BANK_HistoryHandle *
+TALER_BANK_history_range (struct GNUNET_CURL_Context *ctx,
+                          const char *bank_base_url,
+                          const struct TALER_BANK_AuthenticationData *auth,
+                          uint64_t account_number,
+                          enum TALER_BANK_Direction direction,
+                          unsigned int ascending,
+                          struct GNUNET_TIME_Absolute start_date,
+                          struct GNUNET_TIME_Absolute end_date,
+                          TALER_BANK_HistoryResultCallback hres_cb,
+                          void *hres_cb_cls)
+{
+  struct TALER_BANK_HistoryHandle *hh;
+  char *url;
+
+  GNUNET_TIME_round_abs (&start_date);
+  GNUNET_TIME_round_abs (&end_date);
+
+  GNUNET_asprintf (&url,
+                   
"/history-range?auth=basic&account_number=%llu&start=%llu&end=%llu&direction=%s&cancelled=%s&ordering=%s",
+                   (unsigned long long) account_number,
+                   start_date.abs_value_us / 1000LL / 1000LL,
+                   end_date.abs_value_us / 1000LL / 1000LL,
+                   conv_direction (direction).value,
+                   conv_cancel (direction).value,
+                   (GNUNET_YES == ascending) ? "ascending" : "descending");
+
+  hh = put_history_job (ctx,
+                        bank_base_url,
+                        url,
+                        auth,
+                        hres_cb,
+                        hres_cb_cls);
+
+  GNUNET_free (url);
+  return hh;
+}
+
+
+
 /**
  * Request the wire transfer history of a bank account.
  *
  * @param ctx curl context for the event loop
- * @param bank_base_url URL of the bank (used to execute this request)
+ * @param bank_base_url URL of the bank (used to execute this
+ *        request)
  * @param auth authentication data to use
  * @param account_number which account number should we query
- * @param direction what kinds of wire transfers should be returned
- * @param ascending if GNUNET_YES, history elements will be returned in 
chronological order.
- * @param start_row from which row on do we want to get results, use 
UINT64_MAX for the latest; exclusive
- * @param num_results how many results do we want; negative numbers to go into 
the past,
- *                    positive numbers to go into the future starting at @a 
start_row;
- *                    must not be zero.
- * @param hres_cb the callback to call with the transaction history
+ * @param direction what kinds of wire transfers should be
+ *        returned
+ * @param ascending if GNUNET_YES, history elements will
+ *        be returned in chronological order.
+ * @param start_row from which row on do we want to get results,
+ *        use UINT64_MAX for the latest; exclusive
+ * @param num_results how many results do we want;
+ *        negative numbers to go into the past, positive numbers
+ *        to go into the future starting at @a start_row;
+ *        must not be zero.
+ * @param hres_cb the callback to call with the transaction
+ *        history
  * @param hres_cb_cls closure for the above callback
- * @return NULL
- *         if the inputs are invalid (i.e. zero value for @e num_results).
- *         In this case, the callback is not called.
+ * @return NULL if the inputs are invalid (i.e. zero value for
+ *         @e num_results). In this case, the callback is not
+ *         called.
  */
 struct TALER_BANK_HistoryHandle *
 TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
@@ -280,91 +478,45 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
                     void *hres_cb_cls)
 {
   struct TALER_BANK_HistoryHandle *hh;
-  CURL *eh;
   char *url;
-  const char *dir;
-  const char *can;
 
   if (0 == num_results)
   {
     GNUNET_break (0);
     return NULL;
   }
-  if (TALER_BANK_DIRECTION_NONE == direction)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-
-  dir = NULL;
-  if (TALER_BANK_DIRECTION_BOTH == (TALER_BANK_DIRECTION_BOTH & direction))
-    dir = "both";
-  else if (TALER_BANK_DIRECTION_CREDIT == (TALER_BANK_DIRECTION_CREDIT & 
direction))
-    dir = "credit";
-  else if (TALER_BANK_DIRECTION_DEBIT == (TALER_BANK_DIRECTION_BOTH & 
direction))
-    dir = "debit";
-  if (NULL == dir)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-  if (TALER_BANK_DIRECTION_CANCEL == (TALER_BANK_DIRECTION_CANCEL & direction))
-    can = "show";
-  else
-    can = "omit";
 
+  GNUNET_asprintf (&url,
+                   
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s&start=%llu",
+                   (unsigned long long) account_number,
+                   (long long) num_results,
+                   conv_direction (direction).value,
+                   conv_cancel (direction).value,
+                   (GNUNET_YES == ascending) ? "ascending" : "descending",
+                   start_row);
+
+  /* Locate and "cut" the 'start' argument,
+   * if the user didn't provide one.  */
   if (UINT64_MAX == start_row)
-  {
-    GNUNET_asprintf (&url,
-                     
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s",
-                     (unsigned long long) account_number,
-                     (long long) num_results,
-                     dir,
-                     can,
-                     (GNUNET_YES == ascending) ? "ascending" : "descending");
+    *strstr (url,
+             "&start=") = '\0';
 
-  }
-  else
-  {
-    GNUNET_asprintf (&url,
-                     
"/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s&cancelled=%s&ordering=%s",
-                     (unsigned long long) account_number,
-                     (long long) num_results,
-                     (unsigned long long) start_row,
-                     dir,
-                     can,
-                     (GNUNET_YES == ascending) ? "ascending" : "descending");
-  }
+  hh = put_history_job (ctx,
+                        bank_base_url,
+                        url,
+                        auth,
+                        hres_cb,
+                        hres_cb_cls);
 
-  hh = GNUNET_new (struct TALER_BANK_HistoryHandle);
-  hh->hcb = hres_cb;
-  hh->hcb_cls = hres_cb_cls;
-  hh->bank_base_url = GNUNET_strdup (bank_base_url);
-  hh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
-                                             url);
   GNUNET_free (url);
-  hh->authh = TALER_BANK_make_auth_header_ (auth);
-  eh = curl_easy_init ();
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_HTTPHEADER,
-                                   hh->authh));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_URL,
-                                   hh->request_url));
-  hh->job = GNUNET_CURL_job_add (ctx,
-                                 eh,
-                                 GNUNET_NO,
-                                 &handle_history_finished,
-                                 hh);
   return hh;
 }
 
 
 /**
- * Cancel a history request.  This function cannot be used on a request
- * handle if a response is already served for it.
+ * Cancel a history request.  This function cannot be
+ * used on a request handle if a response is already
+ * served for it.
  *
  * @param hh the history request handle
  */
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c
index 09ec1bbe..71dd8bac 100644
--- a/src/bank-lib/fakebank.c
+++ b/src/bank-lib/fakebank.c
@@ -2,16 +2,19 @@
   This file is part of TALER
   (C) 2016, 2017, 2018 Inria and 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
-  Foundation; either version 3, or (at your option) any later version.
-
-  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License along with
-  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+  TALER is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License
+  as published by the Free Software Foundation; either version 3,
+  or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not,
+  see <http://www.gnu.org/licenses/>
 */
 
 /**
@@ -22,6 +25,7 @@
 #include "platform.h"
 #include "taler_fakebank_lib.h"
 #include "taler_bank_service.h"
+#include "fakebank.h"
 
 /**
  * Maximum POST request size (for /admin/add/incoming)
@@ -29,96 +33,6 @@
 #define REQUEST_BUFFER_MAX (4*1024)
 
 
-
-/**
- * Details about a transcation we (as the simulated bank) received.
- */
-struct Transaction
-{
-
-  /**
-   * We store transactions in a DLL.
-   */
-  struct Transaction *next;
-
-  /**
-   * We store transactions in a DLL.
-   */
-  struct Transaction *prev;
-
-  /**
-   * Amount to be transferred.
-   */
-  struct TALER_Amount amount;
-
-  /**
-   * Account to debit.
-   */
-  uint64_t debit_account;
-
-  /**
-   * Account to credit.
-   */
-  uint64_t credit_account;
-
-  /**
-   * Subject of the transfer.
-   */
-  char *subject;
-
-  /**
-   * Base URL of the exchange.
-   */
-  char *exchange_base_url;
-
-  /**
-   * When did the transaction happen?
-   */
-  struct GNUNET_TIME_Absolute date;
-
-  /**
-   * Number of this transaction.
-   */
-  uint64_t row_id;
-
-  /**
-   * Flag set if the transfer was rejected.
-   */
-  int rejected;
-
-  /**
-   * Has this transaction been subjected to #TALER_FAKEBANK_check()
-   * and should thus no longer be counted in
-   * #TALER_FAKEBANK_check_empty()?
-   */
-  int checked;
-};
-
-
-/**
- * Needed to implement ascending/descending ordering
- * of /history results.
- */
-struct HistoryElement
-{
-
-  /**
-   * History JSON element.
-   */
-  json_t *element;
-
-  /**
-   * Previous element.
-   */
-  struct HistoryElement *prev;
-
-  /**
-   * Next element.
-   */
-  struct HistoryElement *next;
-};
-
-
 /**
  * Handle for the fake bank.
  */
@@ -246,11 +160,12 @@ TALER_FAKEBANK_make_transfer (struct 
TALER_FAKEBANK_Handle *h,
   struct Transaction *t;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Making transfer from %llu to %llu over %s and subject %s\n",
+              "Making transfer from %llu to %llu over %s and subject %s; for 
exchange: %s\n",
               (unsigned long long) debit_account,
               (unsigned long long) credit_account,
               TALER_amount2s (amount),
-              subject);
+              subject,
+              exchange_base_url);
   t = GNUNET_new (struct Transaction);
   t->debit_account = debit_account;
   t->credit_account = credit_account;
@@ -482,6 +397,7 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
   uint64_t row_id;
 
   pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+                                connection,
                                 con_cls,
                                 upload_data,
                                 upload_data_size,
@@ -549,9 +465,11 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
     void *json_str;
     size_t json_len;
 
-    json = json_pack ("{s:I}",
+    json = json_pack ("{s:I, s:s}",
                       "row_id",
-                      (json_int_t) row_id);
+                      (json_int_t) row_id,
+                      "timestamp", "/Date(0)/"); /*dummy tmp */
+
     json_str = json_dumps (json,
                            JSON_INDENT(2));
     json_decref (json);
@@ -606,6 +524,7 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,
   int found;
 
   pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+                                connection,
                                 con_cls,
                                 upload_data,
                                 upload_data_size,
@@ -654,10 +573,11 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,
   json_decref (json);
 
   if (GNUNET_OK != found)
-    return create_bank_error (connection,
-                              MHD_HTTP_NOT_FOUND,
-                              TALER_EC_BANK_REJECT_TRANSACTION_NOT_FOUND,
-                              "transaction unknown");
+    return create_bank_error
+      (connection,
+       MHD_HTTP_NOT_FOUND,
+       TALER_EC_BANK_REJECT_TRANSACTION_NOT_FOUND,
+       "transaction unknown");
   /* finally build regular response */
   resp = MHD_create_response_from_buffer (0,
                                           NULL,
@@ -679,153 +599,95 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,
  * @return MHD result code
  */
 static int
+handle_home_page (struct TALER_FAKEBANK_Handle *h,
+                  struct MHD_Connection *connection,
+                  void **con_cls)
+{
+  int ret;
+  struct MHD_Response *resp;
+#define HELLOMSG "Hello, Fakebank!"
+
+  resp = MHD_create_response_from_buffer
+    (strlen (HELLOMSG),
+     HELLOMSG,
+     MHD_RESPMEM_MUST_COPY);
+
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_OK,
+                            resp);
+
+  MHD_destroy_response (resp);
+  return ret;
+}
+
+
+/**
+ * Handle incoming HTTP request for /history
+ *
+ * @param h the fakebank handle
+ * @param connection the connection
+ * @param con_cls place to store state, not used
+ * @return MHD result code
+ */
+static int
 handle_history (struct TALER_FAKEBANK_Handle *h,
                 struct MHD_Connection *connection,
                 void **con_cls)
 {
-  const char *auth;
-  const char *delta;
+  struct HistoryArgs ha;
+  struct HistoryRangeIds hri;
   const char *start;
-  const char *dir;
-  const char *acc;
-  const char *cancelled;
-  const char *ordering;
-  unsigned long long account_number;
-  unsigned long long start_number;
-  long long count;
-  enum TALER_BANK_Direction direction;
+  const char *delta;
   struct Transaction *pos;
-  json_t *history;
-  json_t *jresponse;
-  int ret;
-  int ascending;
-  struct HistoryElement *history_results_head = NULL;
-  struct HistoryElement *history_results_tail = NULL;
-  struct HistoryElement *history_element = NULL;
-
-  auth = MHD_lookup_connection_value (connection,
-                                      MHD_GET_ARGUMENT_KIND,
-                                      "auth");
-  delta = MHD_lookup_connection_value (connection,
-                                       MHD_GET_ARGUMENT_KIND,
-                                       "delta");
-  dir = MHD_lookup_connection_value (connection,
-                                     MHD_GET_ARGUMENT_KIND,
-                                     "direction");
-  cancelled = MHD_lookup_connection_value (connection,
-                                           MHD_GET_ARGUMENT_KIND,
-                                           "cancelled");
-  start = MHD_lookup_connection_value (connection,
-                                       MHD_GET_ARGUMENT_KIND,
-                                       "start");
-  ordering = MHD_lookup_connection_value (connection,
-                                          MHD_GET_ARGUMENT_KIND,
-                                          "ordering");
-  acc = MHD_lookup_connection_value (connection,
-                                     MHD_GET_ARGUMENT_KIND,
-                                     "account_number");
-  if ( (NULL == auth) ||
-       (0 != strcasecmp (auth,
-                         "basic")) ||
-       (NULL == acc) ||
-       (NULL == delta) )
+
+  if (GNUNET_OK != TFH_parse_history_common_args (connection,
+                                                  &ha))
   {
-    /* Invalid request, given that this is fakebank we impolitely just
-       kill the connection instead of returning a nice error. */
     GNUNET_break (0);
     return MHD_NO;
   }
-  start_number = 0;
-  if ( (1 != sscanf (delta,
-                     "%lld",
-                     &count)) ||
-       (1 != sscanf (acc,
-                     "%llu",
-                     &account_number)) ||
-       ( (NULL != start) &&
-         (1 != sscanf (start,
-                       "%llu",
-                       &start_number)) ) ||
-       (NULL == dir) ||
-       (NULL == cancelled) ||
-       ( (0 != strcasecmp (cancelled,
-                           "OMIT")) &&
-         (0 != strcasecmp (cancelled,
-                           "SHOW")) ) ||
-       ( (0 != strcasecmp (dir,
-                           "BOTH")) &&
-         (0 != strcasecmp (dir,
-                           "CREDIT")) &&
-         (0 != strcasecmp (dir,
-                           "DEBIT")) ) )
+
+  start = MHD_lookup_connection_value (connection,
+                                       MHD_GET_ARGUMENT_KIND,
+                                       "start");
+  delta = MHD_lookup_connection_value (connection,
+                                       MHD_GET_ARGUMENT_KIND,
+                                       "delta");
+  if ( ((NULL != start) && (1 != sscanf (start,
+                                        "%llu",
+                                        &hri.start))) ||
+    (NULL == delta) || (1 != sscanf (delta,
+                                     "%lld",
+                                     &hri.count)) )
   {
-    /* Invalid request, given that this is fakebank we impolitely just
-       kill the connection instead of returning a nice error. */
     GNUNET_break (0);
     return MHD_NO;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Client asked for up to %lld results of type %s for account %llu 
starting at %llu\n",
-              count,
-              dir,
-              (unsigned long long) account_number,
-              start_number);
-  if (0 == strcasecmp (dir,
-                       "CREDIT"))
-  {
-    direction = TALER_BANK_DIRECTION_CREDIT;
-  }
-  else if (0 == strcasecmp (dir,
-                            "DEBIT"))
-  {
-    direction = TALER_BANK_DIRECTION_DEBIT;
-  }
-  else if (0 == strcasecmp (dir,
-                            "BOTH"))
-  {
-    direction = TALER_BANK_DIRECTION_BOTH;
-  }
-  else
-  {
-    GNUNET_assert (0);
-    return MHD_NO;
-  }
-  if (0 == strcasecmp (cancelled,
-                       "OMIT"))
-  {
-    /* nothing */
-  } else if (0 == strcasecmp (cancelled,
-                              "SHOW"))
-  {
-    direction |= TALER_BANK_DIRECTION_CANCEL;
-  }
-  else
-  {
-    GNUNET_assert (0);
-    return MHD_NO;
-  }
+  ha.range = &hri;
 
   if (NULL == start)
-    pos = 0 > count ? h->transactions_tail : h->transactions_head;
+    pos = 0 > hri.count ?
+      h->transactions_tail : h->transactions_head;
 
   else if (NULL != h->transactions_head)
   {
     for (pos = h->transactions_head;
          NULL != pos;
          pos = pos->next)
-      if (pos->row_id  == start_number)
+      if (pos->row_id  == hri.start)
         break;
     if (NULL == pos)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Invalid range specified, transaction %llu not known!\n",
-                  (unsigned long long) start_number);
+                  "Invalid range specified,"
+                  " transaction %llu not known!\n",
+                  (unsigned long long) hri.start);
       return MHD_NO;
     }
     /* range is exclusive, skip the matching entry */
-    if (count > 0)
+    if (hri.count > 0)
       pos = pos->next;
-    if (count < 0)
+    if (hri.count < 0)
       pos = pos->prev;
   }
   else
@@ -833,160 +695,83 @@ handle_history (struct TALER_FAKEBANK_Handle *h,
     /* list is empty */
     pos = NULL;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "/history, start row (0 == no transactions exist): %llu\n",
+              NULL != pos ? pos->row_id : 0LL);
+  return TFH_build_history_response (connection,
+                                     pos,
+                                     &ha,
+                                     &TFH_handle_history_skip,
+                                     &TFH_handle_history_step,
+                                     &TFH_handle_history_advance);
+}
 
-  history = json_array ();
-  if ((NULL != ordering)
-      && 0 == strcmp ("ascending",
-                      ordering))
-    ascending = GNUNET_YES;
-  else
-    ascending = GNUNET_NO;
-
-  while ( (NULL != pos) &&
-          (0 != count) )
-  {
-    json_t *trans;
-    char *subject;
-    const char *sign;
-
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Found transaction over %s from %llu to %llu\n",
-                TALER_amount2s (&pos->amount),
-                (unsigned long long) pos->debit_account,
-                (unsigned long long) pos->credit_account);
-
-    if ( (! ( ( (account_number == pos->debit_account) &&
-                (0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
-              ( (account_number == pos->credit_account) &&
-                (0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) ||
-         ( (0 == (direction & TALER_BANK_DIRECTION_CANCEL)) &&
-           (GNUNET_YES == pos->rejected) ) )
-    {
-      if (count > 0)
-        pos = pos->next;
-      if (count < 0)
-        pos = pos->prev;
-      continue;
-    }
-
-    GNUNET_asprintf (&subject,
-                     "%s %s",
-                     pos->subject,
-                     pos->exchange_base_url);
-    sign =
-      (account_number == pos->debit_account)
-      ? (pos->rejected ? "cancel-" : "-")
-      : (pos->rejected ? "cancel+" : "+");
-    trans = json_pack ("{s:I, s:o, s:o, s:s, s:I, s:s}",
-                       "row_id", (json_int_t) pos->row_id,
-                       "date", GNUNET_JSON_from_time_abs (pos->date),
-                       "amount", TALER_JSON_from_amount (&pos->amount),
-                       "sign", sign,
-                       "counterpart", (json_int_t) ( (account_number == 
pos->debit_account)
-                                                     ? pos->credit_account
-                                                     : pos->debit_account),
-                       "wt_subject", subject);
-    GNUNET_assert (NULL != trans);
-    GNUNET_free (subject);
-
-    history_element = GNUNET_new (struct HistoryElement);
-    history_element->element = trans;
-
-    if (((0 < count) && (GNUNET_YES == ascending))
-      || ((0 > count) && (GNUNET_NO == ascending)))
-    GNUNET_CONTAINER_DLL_insert_tail (history_results_head,
-                                      history_results_tail,
-                                      history_element);
-    else
-      GNUNET_CONTAINER_DLL_insert (history_results_head,
-                                   history_results_tail,
-                                   history_element);
-    if (count > 0)
-    {
-      pos = pos->next;
-      count--;
-    }
-    if (count < 0)
-    {
-      pos = pos->prev;
-      count++;
-    }
-  }
-
-  if (NULL != history_results_head)
-    history_element = history_results_head;
-  while (NULL != history_element)
-  {
-    json_array_append_new (history,
-                           history_element->element);
-    history_element = history_element->next;
-    if (NULL != history_element)
-      GNUNET_free_non_null (history_element->prev);
-  }
-  GNUNET_free_non_null (history_results_tail);
+/**
+ * Handle incoming HTTP request for /history-range.
+ *
+ * @param h the fakebank handle
+ * @param connection the connection
+ * @param con_cls place to store state, not used
+ * @return MHD result code
+ */
+static int
+handle_history_range (struct TALER_FAKEBANK_Handle *h,
+                      struct MHD_Connection *connection,
+                      void **con_cls)
+{
+  struct HistoryArgs ha;
+  struct HistoryRangeDates hrd;
+  const char *start;
+  const char *end;
+  long long unsigned int start_stamp;
+  long long unsigned int end_stamp;
+  struct Transaction *pos;
 
-  if (0 == json_array_size (history))
+  if (GNUNET_OK != TFH_parse_history_common_args (connection,
+                                              &ha))
   {
-    struct MHD_Response *resp;
-
-    json_decref (history);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                "Returning empty transaction history\n");
-    resp = MHD_create_response_from_buffer (0,
-                                            "",
-                                            MHD_RESPMEM_PERSISTENT);
-    ret = MHD_queue_response (connection,
-                              MHD_HTTP_NO_CONTENT,
-                              resp);
-    MHD_destroy_response (resp);
-    return ret;
+    GNUNET_break (0);
+    return MHD_NO;
   }
+  start = MHD_lookup_connection_value (connection,
+                                       MHD_GET_ARGUMENT_KIND,
+                                       "start");
+  end = MHD_lookup_connection_value (connection,
+                                     MHD_GET_ARGUMENT_KIND,
+                                     "end");
 
-  jresponse = json_pack ("{s:o}",
-                         "data",
-                         history);
-  if (NULL == jresponse)
+  if ( (NULL == start) || (1 != sscanf (start,
+                                        "%llu",
+                                        &start_stamp)) ||
+    (NULL == end) || (1 != sscanf (end,
+                                   "%lld",
+                                   &end_stamp)) )
   {
     GNUNET_break (0);
     return MHD_NO;
   }
 
-  /* Finally build response object */
-  {
-    struct MHD_Response *resp;
-    void *json_str;
-    size_t json_len;
+  hrd.start.abs_value_us = start_stamp * 1000LL * 1000LL;
+  hrd.end.abs_value_us = end_stamp * 1000LL * 1000LL;
+  ha.range = &hrd;
 
-    json_str = json_dumps (jresponse,
-                           JSON_INDENT(2));
-    json_decref (jresponse);
-    if (NULL == json_str)
-    {
-      GNUNET_break (0);
-      return MHD_NO;
-    }
-    json_len = strlen (json_str);
-    resp = MHD_create_response_from_buffer (json_len,
-                                            json_str,
-                                            MHD_RESPMEM_MUST_FREE);
-    if (NULL == resp)
-    {
-      GNUNET_break (0);
-      free (json_str);
-      return MHD_NO;
-    }
-    (void) MHD_add_response_header (resp,
-                                    MHD_HTTP_HEADER_CONTENT_TYPE,
-                                    "application/json");
-    ret = MHD_queue_response (connection,
-                              MHD_HTTP_OK,
-                              resp);
-    MHD_destroy_response (resp);
+  pos = NULL;
+  /* hunt for 'pos' in the Transaction(s) LL.  */
+  for (pos = h->transactions_head;
+       NULL != pos;
+       pos = pos->next)
+  {
+    if (hrd.start.abs_value_us <= pos->date.abs_value_us)
+      break;
   }
-  return ret;
+  return TFH_build_history_response (connection,
+                                     pos,
+                                     &ha,
+                                     &TFH_handle_history_range_skip,
+                                     TFH_handle_history_range_step,
+                                     &TFH_handle_history_range_advance);
 }
 
-
 /**
  * Handle incoming HTTP request.
  *
@@ -1012,6 +797,18 @@ handle_mhd_request (void *cls,
 {
   struct TALER_FAKEBANK_Handle *h = cls;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Fakebank, serving: %s\n",
+              url);
+
+
+  if ( (0 == strcasecmp (url,
+                         "/")) &&
+       (0 == strcasecmp (method,
+                         MHD_HTTP_METHOD_GET)) )
+    return handle_home_page (h,
+                             connection,
+                             con_cls);
   if ( (0 == strcasecmp (url,
                          "/admin/add/incoming")) &&
        (0 == strcasecmp (method,
@@ -1031,6 +828,13 @@ handle_mhd_request (void *cls,
                           upload_data_size,
                           con_cls);
   if ( (0 == strcasecmp (url,
+                         "/history-range")) &&
+       (0 == strcasecmp (method,
+                         MHD_HTTP_METHOD_GET)) )
+    return handle_history_range (h,
+                                 connection,
+                                 con_cls);
+  if ( (0 == strcasecmp (url,
                          "/history")) &&
        (0 == strcasecmp (method,
                          MHD_HTTP_METHOD_GET)) )
@@ -1178,7 +982,9 @@ TALER_FAKEBANK_start (uint16_t port)
   h = GNUNET_new (struct TALER_FAKEBANK_Handle);
   h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG
 #if EPOLL_SUPPORT
-                                 | MHD_USE_EPOLL
+                                 | MHD_USE_EPOLL_INTERNAL_THREAD
+#else
+                                  | MHD_USE_INTERNAL_POLLING_THREAD
 #endif
                                  | MHD_USE_DUAL_STACK,
                                   port,
diff --git a/src/bank-lib/fakebank.h b/src/bank-lib/fakebank.h
new file mode 100644
index 00000000..f547db52
--- /dev/null
+++ b/src/bank-lib/fakebank.h
@@ -0,0 +1,322 @@
+/*
+  This file is part of TALER
+  (C) 2016, 2017, 2018 Inria and 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 Foundation; either version 3,
+  or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not,
+  see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file bank-lib/fakebank.h
+ * @brief definitions for the "/history[-range]" layer.
+ * @author Marcello Stanisci <address@hidden>
+ */
+
+#ifndef FAKEBANK_H
+#define FAKEBANK_H
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_bank_service.h"
+
+/**
+ * Details about a transcation we (as the simulated bank) received.
+ */
+struct Transaction
+{
+  /**
+   * We store transactions in a DLL.
+   */
+  struct Transaction *next;
+
+  /**
+   * We store transactions in a DLL.
+   */
+  struct Transaction *prev;
+
+  /**
+   * Amount to be transferred.
+   */
+  struct TALER_Amount amount;
+
+  /**
+   * Account to debit.
+   */
+  uint64_t debit_account;
+
+  /**
+   * Account to credit.
+   */
+  uint64_t credit_account;
+
+  /**
+   * Subject of the transfer.
+   */
+  char *subject;
+
+  /**
+   * Base URL of the exchange.
+   */
+  char *exchange_base_url;
+
+  /**
+   * When did the transaction happen?
+   */
+  struct GNUNET_TIME_Absolute date;
+
+  /**
+   * Number of this transaction.
+   */
+  long long unsigned int row_id;
+
+  /**
+   * Flag set if the transfer was rejected.
+   */
+  int rejected;
+
+  /**
+   * Has this transaction been subjected to #TALER_FAKEBANK_check()
+   * and should thus no longer be counted in
+   * #TALER_FAKEBANK_check_empty()?
+   */
+  int checked;
+};
+
+
+/******************************************
+ * Definitions for "/history" start here. *
+ ******************************************/
+
+/**
+ * Needed to implement ascending/descending ordering
+ * of /history results.
+ */
+struct HistoryElement
+{
+
+  /**
+   * History JSON element.
+   */
+  json_t *element;
+
+  /**
+   * Previous element.
+   */
+  struct HistoryElement *prev;
+
+  /**
+   * Next element.
+   */
+  struct HistoryElement *next;
+};
+
+
+/**
+ * Values to implement the "/history-range" range.
+ */
+struct HistoryRangeDates
+{
+  /**
+   * Oldest row in the results.
+   */
+  struct GNUNET_TIME_Absolute start;
+
+  /**
+   * Youngest row in the results.
+   */
+  struct GNUNET_TIME_Absolute end;
+};
+
+/**
+ * Values to implement the "/history" range.
+ */
+struct HistoryRangeIds
+{
+
+  /**
+   * (Exclusive) row ID for the result set.
+   */
+  unsigned long long start;
+
+  /**
+   * How many transactions we want in the result set.  If
+   * negative/positive, @a start will be strictly younger/older
+   * of any element in the result set.
+   */
+  long long count;
+};
+
+
+/**
+ * This is the "base" structure for both the /history and the
+ * /history-range API calls.
+ */
+struct HistoryArgs
+{
+
+  /**
+   * Direction asked by the client: CREDIT / DEBIT / BOTH / CANCEL.
+   */
+  enum TALER_BANK_Direction direction;
+
+  /**
+   * Bank account number of the requesting client.
+   */
+  unsigned long long account_number;
+
+  /**
+   * Ordering of the results.
+   */
+  unsigned int ascending;
+
+  /**
+   * Overloaded type that indicates the "range" to be returned
+   * in the results; this can be either a date range, or a
+   * starting row id + the count.
+   */
+  void *range;
+};
+
+
+
+/**
+ * Type for a function that decides whether or not
+ * the history-building loop should iterate once again.
+ * Typically called from inside the 'while' condition.
+ *
+ * @param ha history argument.
+ * @param pos current position.
+ * @return GNUNET_YES if the iteration shuold go on.
+ */
+typedef int (*CheckAdvance)
+  (const struct HistoryArgs *ha,
+   const struct Transaction *pos);
+
+/**
+ * Type for a function that steps over the next element
+ * in the list of all transactions, after the current @a pos
+ * _got_ included in the result.
+ */
+typedef struct Transaction * (*Step)
+  (const struct HistoryArgs *ha,
+   const struct Transaction *pos);
+
+/*
+ * Type for a function that steps over the next element
+ * in the list of all transactions, after the current @a pos
+ * did _not_ get included in the result.
+ */
+typedef struct Transaction * (*Skip)
+  (const struct HistoryArgs *ha,
+   const struct Transaction *pos);
+
+/**
+ * Actual history response builder.
+ *
+ * @param pos first (included) element in the result set.
+ * @param ha history arguments.
+ * @param caller_name which function is building the history.
+ * @return MHD_YES / MHD_NO, after having enqueued the response
+ *         object into MHD.
+ */
+int
+TFH_build_history_response (struct MHD_Connection *connection,
+                            struct Transaction *pos,
+                            struct HistoryArgs *ha,
+                            Skip skip,
+                            Step step,
+                            CheckAdvance advance);
+
+
+/**
+ * Parse URL history arguments, of _both_ APIs:
+ * /history and /history-range.
+ *
+ * @param connection MHD connection.
+ * @param function_name name of the caller.
+ * @param ha[out] will contain the parsed values.
+ * @return GNUNET_OK only if the parsing succeedes.
+ */
+int
+TFH_parse_history_common_args (struct MHD_Connection *connection,
+                               struct HistoryArgs *ha);
+
+
+/**
+ * Decides whether the history builder will advance or not
+ * to the next element.
+ *
+ * @param ha history args
+ * @return GNUNET_YES/NO to advance/not-advance.
+ */
+int
+TFH_handle_history_advance (const struct HistoryArgs *ha,
+                            const struct Transaction *pos);
+
+/**
+ * Iterates on the "next" element to be processed.  To
+ * be used when the current element does not get inserted in
+ * the result.
+ *
+ * @param ha history arguments.
+ * @param pos current element being processed.
+ * @return the next element to be processed.
+ */
+struct Transaction *
+TFH_handle_history_skip (const struct HistoryArgs *ha,
+                         const struct Transaction *pos);
+
+/**
+ * Iterates on the "next" element to be processed.  To
+ * be used when the current element _gets_ inserted in the result.
+ *
+ * @param ha history arguments.
+ * @param pos current element being processed.
+ * @return the next element to be processed.
+ */
+struct Transaction *
+TFH_handle_history_step (const struct HistoryArgs *ha,
+                         const struct Transaction *pos);
+
+/**
+ * Decides whether the history builder will advance or not
+ * to the next element.
+ *
+ * @param ha history args
+ * @return GNUNET_YES/NO to advance/not-advance.
+ */
+int
+TFH_handle_history_range_advance (const struct HistoryArgs *ha,
+                                  const struct Transaction *pos);
+
+/**
+ * Iterates towards the "next" element to be processed.  To
+ * be used when the current element does not get inserted in
+ * the result.
+ *
+ * @param ha history arguments.
+ * @param pos current element being processed.
+ * @return the next element to be processed.
+ */
+struct Transaction *
+TFH_handle_history_range_skip (const struct HistoryArgs *ha,
+                               const struct Transaction *pos);
+
+/**
+ * Iterates on the "next" element to be processed.  To
+ * be used when the current element _gets_ inserted in the result.
+ * Same implementation of the "skip" counterpart, as /history-range
+ * does not have the notion of count/delta.
+ */
+Step TFH_handle_history_range_step;
+#endif
diff --git a/src/bank-lib/fakebank_history.c b/src/bank-lib/fakebank_history.c
new file mode 100644
index 00000000..17960a4e
--- /dev/null
+++ b/src/bank-lib/fakebank_history.c
@@ -0,0 +1,427 @@
+/*
+  This file is part of TALER
+  (C) 2016, 2017, 2018 Inria and 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 Foundation; either version 3,
+  or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not,
+  see <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file bank-lib/fakebank_history.c
+ * @brief definitions for the "/history[-range]" layer.
+ * @author Marcello Stanisci <address@hidden>
+ */
+
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_json_lib.h"
+#include "fakebank.h"
+
+/**
+ * Decides whether the history builder will advance or not
+ * to the next element.
+ *
+ * @param ha history args
+ * @return GNUNET_YES/NO to advance/not-advance.
+ */
+int
+TFH_handle_history_advance (const struct HistoryArgs *ha,
+                            const struct Transaction *pos)
+{
+  const struct HistoryRangeIds *hri = ha->range;
+
+  return (NULL != pos) && (0 != hri->count);
+}
+
+
+/**
+ * Iterates on the "next" element to be processed.  To
+ * be used when the current element does not get inserted in
+ * the result.
+ *
+ * @param ha history arguments.
+ * @param pos current element being processed.
+ * @return the next element to be processed.
+ */
+struct Transaction *
+TFH_handle_history_skip (const struct HistoryArgs *ha,
+                         const struct Transaction *pos)
+{
+  const struct HistoryRangeIds *hri = ha->range;
+
+  if (hri->count > 0)
+    return pos->next;
+  if (hri->count < 0)
+    return pos->prev;
+  return NULL;
+}
+
+
+/**
+ * Iterates on the "next" element to be processed.  To
+ * be used when the current element _gets_ inserted in the result.
+ *
+ * @param ha history arguments.
+ * @param pos current element being processed.
+ * @return the next element to be processed.
+ */
+struct Transaction *
+TFH_handle_history_step (const struct HistoryArgs *ha,
+                         const struct Transaction *pos)
+{
+  struct HistoryRangeIds *hri = ha->range;
+
+  if (hri->count > 0)
+  {
+    hri->count--;
+    return pos->next;
+  }
+  if (hri->count < 0)
+  {
+    hri->count++;
+    return pos->prev;
+  }
+  return NULL;
+}
+
+
+/**
+ * Decides whether the history builder will advance or not
+ * to the next element.
+ *
+ * @param ha history args
+ * @return GNUNET_YES/NO to advance/not-advance.
+ */
+int
+TFH_handle_history_range_advance (const struct HistoryArgs *ha,
+                                  const struct Transaction *pos)
+{
+  const struct HistoryRangeDates *hrd = ha->range;
+
+  if ( (NULL != pos) &&
+      (pos->date.abs_value_us <= hrd->end.abs_value_us) )
+    return GNUNET_YES;
+
+  return GNUNET_NO;
+}
+
+
+/**
+ * Iterates towards the "next" element to be processed.  To
+ * be used when the current element does not get inserted in
+ * the result.
+ *
+ * @param ha history arguments.
+ * @param pos current element being processed.
+ * @return the next element to be processed.
+ */
+struct Transaction *
+TFH_handle_history_range_skip (const struct HistoryArgs *ha,
+                               const struct Transaction *pos)
+{
+  /* Transactions
+   * are stored from "head"/older to "tail"/younger.  */
+  return pos->next;
+}
+
+/**
+ * Iterates on the "next" element to be processed.  To
+ * be used when the current element _gets_ inserted in the result.
+ * Same implementation of the "skip" counterpart, as /history-range
+ * does not have the notion of count/delta.
+ */
+Step TFH_handle_history_range_step = &TFH_handle_history_range_skip;
+
+/**
+ * Actual history response builder.
+ *
+ * @param pos first (included) element in the result set.
+ * @param ha history arguments.
+ * @param caller_name which function is building the history.
+ * @return MHD_YES / MHD_NO, after having enqueued the response
+ *         object into MHD.
+ */
+int
+TFH_build_history_response (struct MHD_Connection *connection,
+                            struct Transaction *pos,
+                            struct HistoryArgs *ha,
+                            Skip skip,
+                            Step step,
+                            CheckAdvance advance)
+{
+
+  struct HistoryElement *history_results_head = NULL;
+  struct HistoryElement *history_results_tail = NULL;
+  struct HistoryElement *history_element = NULL;
+  json_t *history;
+  json_t *jresponse;
+  int ret;
+
+  while (advance (ha,
+                  pos))
+  {
+    json_t *trans;
+    char *subject;
+    const char *sign;
+
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Found transaction over %s from %llu to %llu\n",
+                TALER_amount2s (&pos->amount),
+                (unsigned long long) pos->debit_account,
+                (unsigned long long) pos->credit_account);
+
+    if ( (! ( ( (ha->account_number == pos->debit_account) &&
+                (0 != (ha->direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
+              ( (ha->account_number == pos->credit_account) &&
+                (0 != (ha->direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) ||
+         ( (0 == (ha->direction & TALER_BANK_DIRECTION_CANCEL)) &&
+           (GNUNET_YES == pos->rejected) ) )
+    {
+      pos = skip (ha,
+                  pos);
+      continue;
+    }
+
+    GNUNET_asprintf (&subject,
+                     "%s %s",
+                     pos->subject,
+                     pos->exchange_base_url);
+    sign =
+      (ha->account_number == pos->debit_account)
+      ? (pos->rejected ? "cancel-" : "-")
+      : (pos->rejected ? "cancel+" : "+");
+    trans = json_pack
+      ("{s:I, s:o, s:o, s:s, s:I, s:s}",
+       "row_id", (json_int_t) pos->row_id,
+       "date", GNUNET_JSON_from_time_abs (pos->date),
+       "amount", TALER_JSON_from_amount (&pos->amount),
+       "sign", sign,
+       "counterpart", (json_int_t)
+         ( (ha->account_number == pos->debit_account)
+            ? pos->credit_account
+            : pos->debit_account),
+       "wt_subject", subject);
+    GNUNET_assert (NULL != trans);
+    GNUNET_free (subject);
+
+    history_element = GNUNET_new (struct HistoryElement);
+    history_element->element = trans;
+
+
+    /* XXX: the ordering feature is missing.  */
+
+    GNUNET_CONTAINER_DLL_insert_tail (history_results_head,
+                                      history_results_tail,
+                                      history_element);
+    pos = step (ha, pos);
+  }
+
+  history = json_array ();
+  if (NULL != history_results_head)
+    history_element = history_results_head;
+
+  while (NULL != history_element)
+  {
+    json_array_append_new (history,
+                           history_element->element);
+    history_element = history_element->next;
+    if (NULL != history_element)
+      GNUNET_free_non_null (history_element->prev);
+  }
+  GNUNET_free_non_null (history_results_tail);
+
+  if (0 == json_array_size (history))
+  {
+    struct MHD_Response *resp;
+
+    json_decref (history);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Returning empty transaction history\n");
+    resp = MHD_create_response_from_buffer
+      (0,
+       "",
+       MHD_RESPMEM_PERSISTENT);
+    ret = MHD_queue_response (connection,
+                              MHD_HTTP_NO_CONTENT,
+                              resp);
+    MHD_destroy_response (resp);
+    return ret;
+  }
+
+  jresponse = json_pack ("{s:o}",
+                         "data",
+                         history);
+  if (NULL == jresponse)
+  {
+    GNUNET_break (0);
+    return MHD_NO;
+  }
+
+  /* Finally build response object */
+  {
+    struct MHD_Response *resp;
+    void *json_str;
+    size_t json_len;
+
+    json_str = json_dumps (jresponse,
+                           JSON_INDENT(2));
+    json_decref (jresponse);
+    if (NULL == json_str)
+    {
+      GNUNET_break (0);
+      return MHD_NO;
+    }
+    json_len = strlen (json_str);
+    resp = MHD_create_response_from_buffer (json_len,
+                                            json_str,
+                                            MHD_RESPMEM_MUST_FREE);
+    if (NULL == resp)
+    {
+      GNUNET_break (0);
+      free (json_str);
+      return MHD_NO;
+    }
+    (void) MHD_add_response_header (resp,
+                                    MHD_HTTP_HEADER_CONTENT_TYPE,
+                                    "application/json");
+    ret = MHD_queue_response (connection,
+                              MHD_HTTP_OK,
+                              resp);
+    MHD_destroy_response (resp);
+  }
+  return ret;
+}
+
+/**
+ * Parse URL history arguments, of _both_ APIs:
+ * /history and /history-range.
+ *
+ * @param connection MHD connection.
+ * @param function_name name of the caller.
+ * @param ha[out] will contain the parsed values.
+ * @return GNUNET_OK only if the parsing succeedes.
+ */
+int
+TFH_parse_history_common_args (struct MHD_Connection *connection,
+                               struct HistoryArgs *ha)
+{
+  /**
+   * @variable
+   * Just check if given and == "basic", no need to keep around.
+   */
+  const char *auth;
+
+  /**
+   * All those will go into the structure, after parsing.
+   */
+  const char *direction;
+  const char *cancelled;
+  const char *ordering;
+  const char *account_number;
+
+
+  auth = MHD_lookup_connection_value (connection,
+                                      MHD_GET_ARGUMENT_KIND,
+                                      "auth");
+  direction = MHD_lookup_connection_value (connection,
+                                           MHD_GET_ARGUMENT_KIND,
+                                           "direction");
+  cancelled = MHD_lookup_connection_value (connection,
+                                           MHD_GET_ARGUMENT_KIND,
+                                           "cancelled");
+  ordering = MHD_lookup_connection_value (connection,
+                                          MHD_GET_ARGUMENT_KIND,
+                                          "ordering");
+  account_number = MHD_lookup_connection_value
+    (connection,
+     MHD_GET_ARGUMENT_KIND,
+     "account_number");
+
+  /* Fail if one of the above failed.  */
+  if ( (NULL == direction) ||
+       (NULL == cancelled) ||
+       ( (0 != strcasecmp (cancelled,
+                           "OMIT")) &&
+         (0 != strcasecmp (cancelled,
+                           "SHOW")) ) ||
+       ( (0 != strcasecmp (direction,
+                           "BOTH")) &&
+         (0 != strcasecmp (direction,
+                           "CREDIT")) &&
+         (0 != strcasecmp (direction,
+                           "DEBIT")) ) ||
+         (1 != sscanf (account_number,
+                       "%llu",
+                       &ha->account_number)) ||
+         ( (NULL == auth) || (0 != strcasecmp (auth,
+                                               "basic")) ) )
+  {
+    /* Invalid request, given that this is fakebank we impolitely
+     * just kill the connection instead of returning a nice error.
+     */
+    GNUNET_break (0);
+    return GNUNET_NO;
+  }
+
+  if (0 == strcasecmp (direction,
+                       "CREDIT"))
+  {
+    ha->direction = TALER_BANK_DIRECTION_CREDIT;
+  }
+  else if (0 == strcasecmp (direction,
+                            "DEBIT"))
+  {
+    ha->direction = TALER_BANK_DIRECTION_DEBIT;
+  }
+  else if (0 == strcasecmp (direction,
+                            "BOTH"))
+  {
+    ha->direction = TALER_BANK_DIRECTION_BOTH;
+  }
+
+  /* Direction is invalid.  */
+  else
+  {
+    GNUNET_break (0);
+    return GNUNET_NO;
+  }
+
+  if (0 == strcasecmp (cancelled,
+                       "OMIT"))
+  {
+    /* nothing */
+  } else if (0 == strcasecmp (cancelled,
+                              "SHOW"))
+  {
+    ha->direction |= TALER_BANK_DIRECTION_CANCEL;
+  }
+
+  /* Cancel-showing policy is invalid.  */
+  else
+  {
+    GNUNET_break (0);
+    return GNUNET_NO;
+  }
+
+  if ((NULL != ordering)
+      && 0 == strcmp ("ascending",
+                      ordering))
+    ha->ascending = GNUNET_YES;
+  else
+    ha->ascending = GNUNET_NO;
+
+  return GNUNET_OK;
+}
+
+
diff --git a/src/bank-lib/taler-bank-transfer.c 
b/src/bank-lib/taler-bank-transfer.c
index d354dafd..2729b7ee 100644
--- a/src/bank-lib/taler-bank-transfer.c
+++ b/src/bank-lib/taler-bank-transfer.c
@@ -115,6 +115,7 @@ do_shutdown (void *cls)
  *                    0 if the bank's reply is bogus (fails to follow the 
protocol)
  * @param ec detailed error code
  * @param serial_id unique ID of the wire transfer in the bank's records; 
UINT64_MAX on error
+ * @param timestamp timestamp when the transaction got settled at the bank.
  * @param json detailed response from the HTTPD, or NULL if reply was not in 
JSON
  */
 static void
@@ -122,6 +123,7 @@ res_cb (void *cls,
         unsigned int http_status,
         enum TALER_ErrorCode ec,
         uint64_t serial_id,
+        struct GNUNET_TIME_Absolute timestamp,
         const json_t *json)
 {
   op = NULL;
diff --git a/src/bank-lib/test_bank_api_new.c b/src/bank-lib/test_bank_api_new.c
index 38ac537f..ab0358c3 100644
--- a/src/bank-lib/test_bank_api_new.c
+++ b/src/bank-lib/test_bank_api_new.c
@@ -40,6 +40,30 @@
 #define CONFIG_FILE "bank.conf"
 
 /**
+ * Add seconds.
+ *
+ * @param base absolute time to add seconds to.
+ * @param relative number of seconds to add.
+ * @return a new absolute time, modified according to @e relative.
+ */
+#define ADDSECS(base, secs) \
+  GNUNET_TIME_absolute_add \
+    (base, \
+     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+                                    secs))
+/**
+ * Subtract seconds.
+ *
+ * @param base absolute time to subtract seconds to.
+ * @param secs relative number of _seconds_ to subtract.
+ * @return a new absolute time, modified according to @e relative.
+ */
+#define SUBSECS(base, secs) \
+  GNUNET_TIME_absolute_subtract \
+    (base, \
+     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+                                    secs))
+/**
  * Bank process.
  */
 struct GNUNET_OS_Process *bankd;
@@ -61,10 +85,7 @@ run (void *cls,
 {
   
   extern struct TALER_BANK_AuthenticationData AUTHS[];
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Bank serves at `%s'\n",
-              bank_url);
+  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
 
   struct TALER_TESTING_Command commands[] = {
 
@@ -76,6 +97,16 @@ run (void *cls,
                                     NULL, /* start */
                                     5),
 
+    TALER_TESTING_cmd_bank_history_range_with_dates
+      ("history-0-range",
+       bank_url,
+       EXCHANGE_ACCOUNT_NUMBER,
+       TALER_BANK_DIRECTION_BOTH,
+       GNUNET_NO,
+       SUBSECS (now,
+                5),
+       ADDSECS (now,
+                5)),
     TALER_TESTING_cmd_fakebank_transfer_with_subject
       ("deposit-1",
        "KUDOS:5.01",
@@ -131,6 +162,20 @@ run (void *cls,
                                     "deposit-1",
                                     5),
 
+    /**
+     * Just check that the two transactions show up.
+     */
+    TALER_TESTING_cmd_bank_history_range_with_dates
+      ("history-2-range",
+       bank_url,
+       EXCHANGE_ACCOUNT_NUMBER,
+       TALER_BANK_DIRECTION_BOTH,
+       GNUNET_NO,
+       SUBSECS (now,
+                50),
+       ADDSECS (now,
+                5)),
+
     TALER_TESTING_cmd_bank_reject ("reject-1",
                                    bank_url,
                                    "deposit-1"),
diff --git a/src/bank-lib/test_bank_api_twisted.c 
b/src/bank-lib/test_bank_api_twisted.c
index 99c33c9a..d01dbad9 100644
--- a/src/bank-lib/test_bank_api_twisted.c
+++ b/src/bank-lib/test_bank_api_twisted.c
@@ -26,17 +26,17 @@
  */
 
 #include "platform.h"
-#include <taler/taler_util.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_exchange_service.h>
-#include <taler/taler_json_lib.h>
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
 #include <gnunet/gnunet_util_lib.h>
 #include <microhttpd.h>
-#include <taler/taler_bank_service.h>
-#include <taler/taler_fakebank_lib.h>
-#include <taler/taler_testing_lib.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
 #include <taler/taler_twister_testing_lib.h>
-#include <taler/taler_testing_bank_lib.h>
+#include "taler_testing_bank_lib.h"
 #include <taler/taler_twister_service.h>
 
 /**
@@ -81,24 +81,23 @@ static void
 run (void *cls,
      struct TALER_TESTING_Interpreter *is)
 {
-
   struct TALER_TESTING_Command commands[] = {
 
+    TALER_TESTING_cmd_wait_service ("wait-service",
+                                    "http://localhost:8888/";),
+
     TALER_TESTING_cmd_bank_history ("history-0",
-                                    twister_url,
+                                    TWISTED_BANK_URL,
                                     EXCHANGE_ACCOUNT_NUMBER,
                                     TALER_BANK_DIRECTION_BOTH,
                                     GNUNET_NO,
                                     NULL,
                                     5),
-    /**
-     * End the suite.  Fixme: better to have a label for this
-     * too, as it shows a "(null)" token on logs.
-     */
     TALER_TESTING_cmd_end ()
   };
 
-  TALER_TESTING_run (is, commands);
+  TALER_TESTING_run (is,
+                     commands);
 }
 
 /**
@@ -109,7 +108,8 @@ run (void *cls,
 static void
 purge_process (struct GNUNET_OS_Process *process)
 {
-  GNUNET_OS_process_kill (process, SIGINT);
+  GNUNET_OS_process_kill (process,
+                          SIGINT);
   GNUNET_OS_process_wait (process);
   GNUNET_OS_process_destroy (process);
 }
@@ -124,14 +124,16 @@ main (int argc,
   unsetenv ("XDG_CONFIG_HOME");
 
   GNUNET_log_setup ("test-bank-api-twisted",
-                    "DEBUG", NULL);
+                    "DEBUG",
+                    NULL);
 
   if (NULL == (bank_url = TALER_TESTING_prepare_bank
       (CONFIG_FILE)))
     return 77;
 
   if (NULL == (bankd = TALER_TESTING_run_bank
-      (CONFIG_FILE, bank_url)))
+      (CONFIG_FILE,
+       bank_url)))
     return 77;
 
   if (NULL == (twister_url = TALER_TESTING_prepare_twister
diff --git a/src/bank-lib/test_bank_api_with_fakebank_new.c 
b/src/bank-lib/test_bank_api_with_fakebank_new.c
index b8eaabea..8865cc40 100644
--- a/src/bank-lib/test_bank_api_with_fakebank_new.c
+++ b/src/bank-lib/test_bank_api_with_fakebank_new.c
@@ -63,12 +63,6 @@ run (void *cls,
 
   struct TALER_TESTING_Command commands[] = {
 
-    /**
-     * NOTE: this command uses internally the _fakebank_ version
-     * of the add-incoming command.  However, this does seem to
-     * work fine against the Python bank too!  Some renaming is
-     * required..
-     */
     TALER_TESTING_cmd_bank_history ("history-0",
                                     fakebank_url,
                                     BANK_ACCOUNT_NUMBER,
diff --git a/src/bank-lib/test_bank_api_with_fakebank_twisted.c 
b/src/bank-lib/test_bank_api_with_fakebank_twisted.c
index fdd18eb2..2b4a5493 100644
--- a/src/bank-lib/test_bank_api_with_fakebank_twisted.c
+++ b/src/bank-lib/test_bank_api_with_fakebank_twisted.c
@@ -25,17 +25,17 @@
  */
 
 #include "platform.h"
-#include <taler/taler_util.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_exchange_service.h>
-#include <taler/taler_json_lib.h>
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
 #include <gnunet/gnunet_util_lib.h>
 #include <microhttpd.h>
-#include <taler/taler_bank_service.h>
-#include <taler/taler_fakebank_lib.h>
-#include <taler/taler_testing_lib.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
 #include <taler/taler_twister_testing_lib.h>
-#include <taler/taler_testing_bank_lib.h>
+#include "taler_testing_bank_lib.h"
 #include <taler/taler_twister_service.h>
 
 /**
@@ -75,18 +75,23 @@ static void
 run (void *cls,
      struct TALER_TESTING_Interpreter *is)
 {
+
   struct TALER_TESTING_Command commands[] = {
+    
+    /**
+     * Can't use the "wait service" CMD here because the
+     * fakebank runs inside the same process of the test.
+     */
+    TALER_TESTING_cmd_wait_service ("wait-service",
+                                    TWISTED_BANK_URL),
+
     TALER_TESTING_cmd_bank_history ("history-0",
-                                    fakebank_url,
+                                    TWISTED_BANK_URL,
                                     EXCHANGE_ACCOUNT_NUMBER,
                                     TALER_BANK_DIRECTION_BOTH,
                                     GNUNET_NO,
                                     NULL,
                                     5),
-    /**
-     * End the suite.  Fixme: better to have a label for this
-     * too, as it shows a "(null)" token on logs.
-     */
     TALER_TESTING_cmd_end ()
   };
 
@@ -120,8 +125,9 @@ main (int argc,
   unsetenv ("XDG_DATA_HOME");
   unsetenv ("XDG_CONFIG_HOME");
 
-  GNUNET_log_setup ("test-bank-api-twisted",
-                    "DEBUG", NULL);
+  GNUNET_log_setup ("test-bank-api-with-fakebank-twisted",
+                    "DEBUG",
+                    NULL);
 
   if (NULL == (fakebank_url = TALER_TESTING_prepare_fakebank
                (CONFIG_FILE,
diff --git a/src/bank-lib/test_bank_interpreter.c 
b/src/bank-lib/test_bank_interpreter.c
index fc765779..9430e84b 100644
--- a/src/bank-lib/test_bank_interpreter.c
+++ b/src/bank-lib/test_bank_interpreter.c
@@ -530,6 +530,7 @@ next (struct InterpreterState *is)
  *                    0 if the bank's reply is bogus (fails to follow the 
protocol)
  * @param ec taler status code
  * @param row_id unique ID of the wire transfer in the bank's records; 
UINT64_MAX on error
+ * @param timestamp time stamp of when the transaction settled at the bank
  * @param json detailed response from the HTTPD, or NULL if reply was not in 
JSON
  */
 static void
@@ -537,6 +538,7 @@ add_incoming_cb (void *cls,
                  unsigned int http_status,
                  enum TALER_ErrorCode ec,
                  uint64_t row_id,
+                 struct GNUNET_TIME_Absolute timestamp,
                  const json_t *json)
 {
   struct InterpreterState *is = cls;
diff --git a/src/bank-lib/testing_api_cmd_history.c 
b/src/bank-lib/testing_api_cmd_history.c
index e3b05c83..013bb647 100644
--- a/src/bank-lib/testing_api_cmd_history.c
+++ b/src/bank-lib/testing_api_cmd_history.c
@@ -40,19 +40,16 @@
  */
 struct HistoryState
 {
-
   /**
    * Base URL of the bank offering the "history" operation.
    */
   const char *bank_url;
 
-
   /**
    * Account number to ask the history for.
    */
   uint64_t account_no;
 
-
   /**
    * Which type of records we are interested: in-transfers
    * / out-transfers / rejected transfers.
@@ -65,7 +62,9 @@ struct HistoryState
   const char *start_row_reference;
 
   /**
-   * How many rows we want in the result.
+   * How many rows we want in the result, _at most_.  In
+   * the case of /history-range, we fake this value with
+   * INT64_MAX.
    */
   long long num_results;
 
@@ -90,6 +89,27 @@ struct HistoryState
    * chronological order.
    */
   unsigned int ascending;
+
+  /**********************************
+   * Following defs are specific to *
+   * the "/history-range" version.  *
+   **********************************/
+
+  /**
+   * Last row number we want in the result.  Only used
+   * as a trait source when using the /history-range API.
+   */
+  const char *end_row_reference;
+
+  /**
+   * Start date for /history-range.
+   */
+  struct GNUNET_TIME_Absolute start_date;
+
+  /**
+   * End date for /history-range.
+   */
+  struct GNUNET_TIME_Absolute end_date;
 };
 
 /**
@@ -242,6 +262,45 @@ print_expected (struct History *h,
   }
 }
 
+
+
+/**
+ * Tell if the current item is beyond the allowed limit.
+ *
+ * @param total current number of items in the built history list.
+ *        Note, this is the list we build locally and compare with
+ *        what the server returned.
+ * @param hs the history CMD state.
+ * @param pos current item to be evaluated or not (if the list
+ *        has already enough elements).
+ * @return GNUNET_OK / GNUNET_NO.
+ */
+static int
+build_history_hit_limit (uint64_t total,
+                         const struct HistoryState *hs,
+                         const struct TALER_TESTING_Command *pos)
+{
+  /* "/history-range" case.  */
+  if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
+    hs->start_date.abs_value_us)
+  {
+    const struct GNUNET_TIME_Absolute *timestamp;
+
+    GNUNET_assert (GNUNET_OK ==
+      TALER_TESTING_get_trait_absolute_time (pos,
+                                             0,
+                                             &timestamp)); 
+
+    GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
+                   hs->end_date.abs_value_us);
+
+    return timestamp->abs_value_us >= hs->end_date.abs_value_us;
+  }
+
+  return total >= hs->num_results;
+}
+
+
 /**
  * This function constructs the list of history elements that
  * interest the account number of the caller.  It has two main
@@ -284,10 +343,10 @@ build_history (struct TALER_TESTING_Interpreter *is,
 
   if (NULL != hs->start_row_reference)
   {
-    TALER_LOG_INFO ("`%s': start row given via reference `%s'\n",
-                    TALER_TESTING_interpreter_get_current_label
-                      (is),
-                    hs->start_row_reference);
+    TALER_LOG_INFO
+      ("`%s': start row given via reference `%s'\n",
+         TALER_TESTING_interpreter_get_current_label  (is),
+         hs->start_row_reference);
     add_incoming_cmd = TALER_TESTING_interpreter_lookup_command
       (is, hs->start_row_reference);
     GNUNET_assert (NULL != add_incoming_cmd);
@@ -295,10 +354,13 @@ build_history (struct TALER_TESTING_Interpreter *is,
       (add_incoming_cmd, 0, &row_id_start));
   }
 
-  GNUNET_assert (0 != hs->num_results);
+  GNUNET_assert ((0 != hs->num_results) || /* "/history" */
+    (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != /* "/history-range" */
+      hs->start_date.abs_value_us));
 
   if (0 == is->ip)
   {
+    TALER_LOG_DEBUG ("Checking history at first CMD..\n");
     *rh = NULL;
     return 0;
   }
@@ -323,9 +385,9 @@ build_history (struct TALER_TESTING_Interpreter *is,
   if (NULL == row_id_start)
     ok = GNUNET_YES;
 
-  /* This loop counts how many commands in the list off _all_
-   * the commands belong to the history of the caller.  This
-   * is stored in the @var total variable.  */
+  /* This loop counts how many commands _later than "start"_ belong
+   * to the history of the caller.  This is stored in the @var total
+   * variable.  */
   for (unsigned int off = start;off != end + inc; off += inc)
   {
     const struct TALER_TESTING_Command *pos = &is->commands[off];
@@ -337,11 +399,12 @@ build_history (struct TALER_TESTING_Interpreter *is,
      * that do not offer a "row_id" trait.  Such skipped CMDs are
      * not interesting for building a history.
      */
-
-    if (GNUNET_OK != TALER_TESTING_get_trait_uint64
-        (pos, 0, &row_id))
+    if (GNUNET_OK != TALER_TESTING_get_trait_uint64 (pos,
+                                                     0,
+                                                     &row_id))
       continue;
 
+    /* Seek "/history" starting row.  */
     if (NULL != row_id_start)
     {
       if (*row_id_start == *row_id)
@@ -352,12 +415,42 @@ build_history (struct TALER_TESTING_Interpreter *is,
         continue;
       }
     }
+
+    /* Seek "/history-range" starting row, _if_ that's the case */
+    if ((GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
+        hs->start_date.abs_value_us) && (GNUNET_YES != ok))
+    {
+      const struct GNUNET_TIME_Absolute *timestamp;
+
+      TALER_TESTING_get_trait_absolute_time (pos,
+                                             0,
+                                             &timestamp);
+      TALER_LOG_DEBUG
+        ("Seeking first row, start vs timestamp: %llu vs %llu\n",
+         (long long unsigned int) hs->start_date.abs_value_us,
+         (long long unsigned int) timestamp->abs_value_us);
+
+      if (hs->start_date.abs_value_us <= timestamp->abs_value_us)
+      {
+        total = 0;
+        ok = GNUNET_YES;
+        continue;
+      }
+    }
+
     /* when 'start' was _not_ given, then ok == GNUNET_YES */
     if (GNUNET_NO == ok)
       continue; /* skip until we find the marker */
 
-    if (total >= hs->num_results * inc)
-      break; /* hit limit specified by command */
+    TALER_LOG_DEBUG ("Found first row\n");
+
+    if (build_history_hit_limit (total,
+                                 hs,
+                                 pos))
+    {
+      TALER_LOG_DEBUG ("Hit history limit\n");
+      break;
+    }
 
     cancelled = test_cancelled (is, off);
 
@@ -396,11 +489,11 @@ build_history (struct TALER_TESTING_Interpreter *is,
     }
   }
 
-
   GNUNET_assert (GNUNET_YES == ok);
 
   if (0 == total)
   {
+    TALER_LOG_DEBUG ("Checking history at first CMD.. (2)\n");
     *rh = NULL;
     return 0;
   }
@@ -414,7 +507,6 @@ build_history (struct TALER_TESTING_Interpreter *is,
   if (NULL == row_id_start)
     ok = GNUNET_YES;
 
-
   /**
    * This loop _only_ populates the array of history elements.
    */
@@ -436,12 +528,41 @@ build_history (struct TALER_TESTING_Interpreter *is,
 
       if (*row_id_start == *row_id)
       {
-        /* Doesn't count, start is excluded from output. */
+        /**
+         * Warning: this zeroing is superfluous, as
+         * total doesn't get incremented if 'start'
+         * was given and couldn't be found. 
+         */
         total = 0;
         ok = GNUNET_YES;
         continue;
       }
     }
+
+    /* Seek "/history-range" starting row, _if_ that's the case */
+    if ((GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
+        hs->start_date.abs_value_us) && (GNUNET_YES != ok))
+    {
+      const struct GNUNET_TIME_Absolute *timestamp;
+
+      TALER_TESTING_get_trait_absolute_time (pos,
+                                             0,
+                                             &timestamp);
+      TALER_LOG_DEBUG
+        ("Seeking first row, start vs timestamp (2): %llu vs %llu\n",
+         (long long unsigned int) hs->start_date.abs_value_us,
+         (long long unsigned int) timestamp->abs_value_us);
+
+      if (hs->start_date.abs_value_us <= timestamp->abs_value_us)
+      {
+        total = 0;
+        ok = GNUNET_YES;
+        continue;
+      }
+    }
+
+    TALER_LOG_INFO ("Found first row (2)\n");
+
     if (GNUNET_NO == ok)
     {
       TALER_LOG_INFO ("Skip on `%s'\n",
@@ -449,9 +570,11 @@ build_history (struct TALER_TESTING_Interpreter *is,
       continue; /* skip until we find the marker */
     }
 
-    if (total >= hs->num_results * inc)
+    if (build_history_hit_limit (total,
+                                 hs,
+                                 pos))
     {
-      TALER_LOG_INFO ("hit limit specified by command\n");
+      TALER_LOG_INFO ("Hit history limit (2)\n");
       break;
     }
 
@@ -469,6 +592,12 @@ build_history (struct TALER_TESTING_Interpreter *is,
                     (unsigned long long) *credit_account_no,
                     (unsigned long long) hs->account_no);
 
+    /**
+     * Discard transactions where the audited account played
+     * _both_ the credit and the debit roles, but _only if_
+     * the audit goes on both directions..  This needs more
+     * explaination!
+     */
     if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
            (hs->account_no == *credit_account_no)) &&
          ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
@@ -492,6 +621,10 @@ build_history (struct TALER_TESTING_Interpreter *is,
       GNUNET_assert (NULL != bank_hostname);
       bank_hostname += 3;
 
+    /* Next two blocks only put the 'direction' and 'banking'
+     * information.  */
+
+    /* Asked for credit, and account got the credit.  */
     if ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
          (hs->account_no == *credit_account_no))
     {
@@ -507,6 +640,8 @@ build_history (struct TALER_TESTING_Interpreter *is,
           bank_hostname,
           (unsigned long long) *debit_account_no);
     }
+
+    /* Asked for debit, and account got the debit.  */
     if ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
            (hs->account_no == *debit_account_no))
     {
@@ -522,6 +657,9 @@ build_history (struct TALER_TESTING_Interpreter *is,
           bank_hostname,
           (unsigned long long) *credit_account_no);
     }
+
+    /* This block _completes_ the information of the current item,
+     * with amount / subject / exchange URL.  */
     if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
            (hs->account_no == *credit_account_no)) ||
          ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
@@ -669,7 +807,8 @@ history_cb (void *cls,
   struct TALER_TESTING_Interpreter *is = cls;
   struct HistoryState *hs = is->commands[is->ip].cls;
 
-  if (MHD_HTTP_OK != http_status)
+  /*NOTE: "204 No Content" is used to signal the end of results.*/
+  if (MHD_HTTP_NO_CONTENT == http_status)
   {
     hs->hh = NULL;
     if ( (hs->results_obtained != compute_result_count (is)) ||
@@ -696,6 +835,19 @@ history_cb (void *cls,
     TALER_TESTING_interpreter_next (is);
     return;
   }
+  
+  if (MHD_HTTP_OK != http_status)
+  {
+    hs->hh = NULL;
+    GNUNET_log
+      (GNUNET_ERROR_TYPE_ERROR,
+       "Unwanted response code from /history[-range]: %u\n",
+       http_status);
+    TALER_TESTING_interpreter_fail (is);
+    return;
+  }
+
+  /* check current element */
   if (GNUNET_OK != check_result (is,
                                  hs->results_obtained,
                                  dir,
@@ -710,7 +862,7 @@ history_cb (void *cls,
                         JSON_COMPACT);
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Result %u was `%s'\n",
-                  (unsigned int) hs->results_obtained,
+                  (unsigned int) hs->results_obtained++,
                   acc);
       if (NULL != acc)
         free (acc);
@@ -751,14 +903,14 @@ history_run (void *cls,
     if (NULL == history_cmd)
       TALER_TESTING_FAIL (is);
 
-    if (GNUNET_OK != TALER_TESTING_get_trait_uint64
-        (history_cmd, 0, &row_id_ptr))
+    if (GNUNET_OK != TALER_TESTING_get_trait_uint64 (history_cmd,
+                                                     0,
+                                                     &row_id_ptr))
       TALER_TESTING_FAIL (is);
     row_id = *row_id_ptr;
 
     TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
                      (unsigned long long) row_id);
-
   }
 
   auth = &AUTHS[hs->account_no - 1];
@@ -777,6 +929,87 @@ history_run (void *cls,
 
 
 /**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+history_range_run (void *cls,
+                   const struct TALER_TESTING_Command *cmd,
+                   struct TALER_TESTING_Interpreter *is)
+{
+  
+  struct HistoryState *hs = cls;
+  const struct GNUNET_TIME_Absolute *start_date;
+  const struct GNUNET_TIME_Absolute *end_date;
+  struct TALER_BANK_AuthenticationData *auth;
+
+  if (NULL != hs->start_row_reference)
+  {
+      
+    const struct TALER_TESTING_Command *history_cmd;
+
+    history_cmd = TALER_TESTING_interpreter_lookup_command
+      (is, hs->start_row_reference);
+
+    if (NULL == history_cmd)
+      TALER_TESTING_FAIL (is);
+
+    if (GNUNET_OK != TALER_TESTING_get_trait_absolute_time
+        (history_cmd, 0, &start_date))
+      TALER_TESTING_FAIL (is);
+    hs->start_date = *start_date;
+  }
+  else
+  {
+    /* no trait wanted.  */
+    GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
+                   hs->start_date.abs_value_us);
+    start_date = &hs->start_date;
+  }
+
+  if (NULL != hs->end_row_reference)
+  {
+
+    const struct TALER_TESTING_Command *history_cmd;
+
+    history_cmd = TALER_TESTING_interpreter_lookup_command
+      (is, hs->end_row_reference);
+
+    if (NULL == history_cmd)
+      TALER_TESTING_FAIL (is);
+
+    if (GNUNET_OK != TALER_TESTING_get_trait_absolute_time
+        (history_cmd, 0, &end_date))
+      TALER_TESTING_FAIL (is);
+    hs->end_date = *end_date;
+  }
+  else
+  {
+    /* no trait wanted.  */
+    GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us !=
+                   hs->end_date.abs_value_us);
+    end_date = &hs->end_date;
+  }
+
+  auth = &AUTHS[hs->account_no - 1];
+  hs->hh = TALER_BANK_history_range (is->ctx,
+                                     hs->bank_url,
+                                     auth,
+                                     hs->account_no,
+                                     hs->direction,
+                                     hs->ascending,
+                                     *start_date,
+                                     *end_date,
+                                     &history_cb,
+                                     is);
+  GNUNET_assert (NULL != hs->hh);
+}
+
+
+/**
  * Free the state from a "history" CMD, and possibly cancel
  * a pending operation thereof.
  *
@@ -836,6 +1069,8 @@ TALER_TESTING_cmd_bank_history
   hs->start_row_reference = start_row_reference;
   hs->num_results = num_results;
   hs->ascending = ascending;
+  hs->start_date = GNUNET_TIME_UNIT_FOREVER_ABS;
+  hs->end_date = GNUNET_TIME_UNIT_FOREVER_ABS;
 
   struct TALER_TESTING_Command cmd = {
     .label = label,
@@ -848,4 +1083,105 @@ TALER_TESTING_cmd_bank_history
   return cmd;
 }
 
+
+/**
+ * Make a "history-range" CMD, picking dates from traits.
+ *
+ * @param label command label.
+ * @param bank_url base URL of the bank offering the "history"
+ *        operation.
+ * @param account_no bank account number to ask the history for.
+ * @param direction which direction this operation is interested.
+ * @param ascending if GNUNET_YES, the bank will return the rows
+ *        in ascending (= chronological) order.
+ * @param start_row_reference reference to a command that can
+ *        offer a absolute time to use as the 'start' argument
+ *        for "/history-range".
+ * @param end_row_reference reference to a command that can
+ *        offer a absolute time to use as the 'end' argument
+ *        for "/history-range".
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_history_range
+  (const char *label,
+   const char *bank_url,
+   uint64_t account_no,
+   enum TALER_BANK_Direction direction,
+   unsigned int ascending,
+   const char *start_row_reference,
+   const char *end_row_reference)
+{
+  struct HistoryState *hs;
+
+  hs = GNUNET_new (struct HistoryState);
+  hs->bank_url = bank_url;
+  hs->account_no = account_no;
+  hs->direction = direction;
+  hs->start_row_reference = start_row_reference;
+  hs->end_row_reference = end_row_reference;
+  hs->ascending = ascending;
+  hs->start_date = GNUNET_TIME_UNIT_FOREVER_ABS;
+  hs->end_date = GNUNET_TIME_UNIT_FOREVER_ABS;
+
+  struct TALER_TESTING_Command cmd = {
+    .label = label,
+    .cls = hs,
+    .run = &history_range_run,
+    .cleanup = &history_cleanup,
+    .traits = &history_traits
+  };
+
+  return cmd;
+}
+
+
+/**
+ * Make a "history-range" CMD, picking dates from the arguments.
+ *
+ * @param label command label.
+ * @param bank_url base URL of the bank offering the "history"
+ *        operation.
+ * @param account_no bank account number to ask the history for.
+ * @param direction which direction this operation is interested.
+ * @param ascending if GNUNET_YES, the bank will return the rows
+ *        in ascending (= chronological) order.
+ * @param start_date value for the 'start' argument
+ *        of "/history-range".
+ * @param end_date value for the 'end' argument
+ *        of "/history-range".
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_history_range_with_dates
+  (const char *label,
+   const char *bank_url,
+   uint64_t account_no,
+   enum TALER_BANK_Direction direction,
+   unsigned int ascending,
+   struct GNUNET_TIME_Absolute start_date,
+   struct GNUNET_TIME_Absolute end_date)
+{
+  struct HistoryState *hs;
+
+  hs = GNUNET_new (struct HistoryState);
+  hs->bank_url = bank_url;
+  hs->account_no = account_no;
+  hs->direction = direction;
+  hs->ascending = ascending;
+  hs->start_row_reference = NULL;
+  hs->start_date = start_date;
+  hs->end_date = end_date;
+
+  struct TALER_TESTING_Command cmd = {
+    .label = label,
+    .cls = hs,
+    .run = &history_range_run,
+    .cleanup = &history_cleanup,
+    .traits = &history_traits
+  };
+
+  return cmd;
+}
+
 /* end of testing_api_cmd_history.c */
diff --git a/src/benchmark/taler-exchange-benchmark.c 
b/src/benchmark/taler-exchange-benchmark.c
index 59fcc659..56928351 100644
--- a/src/benchmark/taler-exchange-benchmark.c
+++ b/src/benchmark/taler-exchange-benchmark.c
@@ -566,6 +566,7 @@ parallel_benchmark (TALER_TESTING_Main main_cb,
   struct GNUNET_OS_Process *exchanged = NULL;
   struct GNUNET_OS_Process *wirewatch = NULL;
   struct GNUNET_OS_Process *exchange_slave = NULL;
+  struct GNUNET_DISK_PipeHandle *exchange_slave_pipe;
 
   if ( (MODE_CLIENT == mode) || (MODE_BOTH == mode) )
   {
@@ -650,9 +651,14 @@ parallel_benchmark (TALER_TESTING_Main main_cb,
                 "remote command: %s\n",
                 remote_cmd);
 
+    GNUNET_assert (NULL != (exchange_slave_pipe =
+                            GNUNET_DISK_pipe (GNUNET_YES,
+                                              GNUNET_YES,
+                                              0, 0)));
+
     exchange_slave = GNUNET_OS_start_process (GNUNET_NO,
-                                              GNUNET_OS_INHERIT_STD_ALL,
-                                              NULL, NULL, NULL,
+                                              
GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
+                                              exchange_slave_pipe, NULL, NULL,
                                               "ssh",
                                               "ssh",
                                               /* Don't ask for pw/passphrase, 
rather fail */
@@ -758,8 +764,19 @@ parallel_benchmark (TALER_TESTING_Main main_cb,
 
   if (MODE_CLIENT == mode)
   {
+    char c = 'q';
+
     GNUNET_assert (NULL != exchange_slave);
-    GNUNET_OS_process_kill (exchange_slave, SIGTERM);
+
+    /* Write a character to the pipe to end the exchange slave.
+     * We can't send a signal here, as it would just kill SSH and
+     * not necessarily the process on the other machine. */
+    GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
+                            (exchange_slave_pipe, GNUNET_DISK_PIPE_END_WRITE),
+                            &c, sizeof (c));
+
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_OS_process_wait (exchange_slave));
     GNUNET_OS_process_destroy (exchange_slave);
   }
 
@@ -816,8 +833,8 @@ int
 main (int argc,
       char *const *argv)
 {
-  char *exchange_url;
-  char *auditor_url;
+  char *exchange_url = NULL;
+  char *auditor_url = NULL;
   struct GNUNET_CONFIGURATION_Handle *cfg;
   struct GNUNET_GETOPT_CommandLineOption options[] = {
     GNUNET_GETOPT_option_mandatory
@@ -1031,8 +1048,14 @@ main (int argc,
                                NULL,
                                cfg_filename,
                                exchange_url);
-  GNUNET_free (exchange_url);
-  GNUNET_free (auditor_url);
+
+  GNUNET_free_non_null (exchange_url);
+  GNUNET_free_non_null (auditor_url);
+
+  /* If we're the exchange worker, we're done now.  No need to print results */
+  if (MODE_EXCHANGE == mode)
+    return (GNUNET_OK == result) ? 0 : result;
+
   duration = GNUNET_TIME_absolute_get_duration (start_time);
   if (GNUNET_OK == result)
   {
diff --git a/src/exchange-tools/taler-exchange-keycheck.c 
b/src/exchange-tools/taler-exchange-keycheck.c
index d5823773..c657454a 100644
--- a/src/exchange-tools/taler-exchange-keycheck.c
+++ b/src/exchange-tools/taler-exchange-keycheck.c
@@ -163,9 +163,8 @@ denomkeys_iter (void *cls,
   }
   GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
                                      &hc);
-  if (0 != memcmp (&hc,
-                   &dki->issue.properties.denom_hash,
-                   sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (&hc,
+                          &dki->issue.properties.denom_hash))
   {
     fprintf (stderr,
              "Public key for `%s' does not match signature\n",
diff --git a/src/exchange-tools/taler-exchange-keyup.c 
b/src/exchange-tools/taler-exchange-keyup.c
index caa685a3..28e2ea1d 100644
--- a/src/exchange-tools/taler-exchange-keyup.c
+++ b/src/exchange-tools/taler-exchange-keyup.c
@@ -195,12 +195,18 @@ static char *feedir;
 static const struct GNUNET_CONFIGURATION_Handle *kcfg;
 
 /**
- * Time when the key update is executed.  Either the actual current time, or a
- * pretended time.
+ * Time when the key update is executed.
+ * Either the actual current time, or a pretended time.
  */
 static struct GNUNET_TIME_Absolute now;
 
 /**
+ * The time for the key update, as passed by the user
+ * on the command line.
+ */
+static struct GNUNET_TIME_Absolute now_tmp;
+
+/**
  * Master private key of the exchange.
  */
 static struct TALER_MasterPrivateKeyP master_priv;
@@ -373,9 +379,9 @@ get_anchor_iter (void *cls,
        (0 != *end) ||
        (0 > bval) )
   {
-    fprintf(stderr,
-            "Ignoring unexpected file `%s'.\n",
-            filename);
+    fprintf (stderr,
+             "Ignoring unexpected file `%s'.\n",
+             filename);
     return GNUNET_OK;
   }
   stamp.abs_value_us = (uint64_t) bval;
@@ -433,12 +439,12 @@ get_anchor (const char *dir,
   }
   else if (anchor->abs_value_us != now.abs_value_us)
   {
-    /* Real starting time is the last start time + duration - overlap */
     *anchor = GNUNET_TIME_absolute_add (*anchor,
                                         duration);
     *anchor = GNUNET_TIME_absolute_subtract (*anchor,
                                              overlap);
   }
+
   /* anchor is now the stamp where we need to create a new key */
 }
 
@@ -726,6 +732,12 @@ get_cointype_params (const char *ct,
               params->duration_withdraw,
               params->duration_overlap,
               &params->anchor);
+
+  /**
+   * The "anchor" is merely the latest denom key filename
+   * converted to a GNUnet absolute date.
+   */
+
   return GNUNET_OK;
 }
 
@@ -809,6 +821,7 @@ exchange_keys_update_cointype (void *cls,
     *ret = GNUNET_SYSERR;
     return;
   }
+  /* p has the right anchor now = latest denom filename converted to time.  */
   if (GNUNET_OK !=
       GNUNET_DISK_directory_create (get_cointype_dir (&p)))
   {
@@ -825,7 +838,6 @@ exchange_keys_update_cointype (void *cls,
                   (GNUNET_TIME_absolute_get_difference (p.anchor,
                                                         lookahead_sign_stamp),
                                                         GNUNET_NO));
-
     dkf = get_cointype_file (&p,
                              p.anchor);
     GNUNET_break (GNUNET_YES !=
@@ -1174,11 +1186,19 @@ run (void *cls,
      const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  static struct GNUNET_HashCode zero;
   struct GNUNET_TIME_Relative lookahead_sign;
   struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
 
   kcfg = cfg;
+
+  if (now.abs_value_us != now_tmp.abs_value_us)
+  {
+    /* The user gave "--now", use it */ 
+    now = now_tmp;
+  }
+  /* The user _might_ have given "--now" but it matched
+   * exactly the normal now, so no change required.  */
+
   if (NULL == feedir)
   {
     if (GNUNET_OK !=
@@ -1278,9 +1298,8 @@ run (void *cls,
       return;
     }
     if (0 !=
-        memcmp (&master_public_key,
-                &master_public_key_from_cfg,
-                sizeof (struct TALER_MasterPublicKeyP)))
+        GNUNET_memcmp (&master_public_key,
+                       &master_public_key_from_cfg))
     {
       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
                                  "exchange",
@@ -1333,9 +1352,7 @@ run (void *cls,
     global_ret = 1;
     return;
   }
-  if ( (0 != memcmp (&zero,
-                     &revoke_dkh,
-                     sizeof (zero))) &&
+  if ( (0 != GNUNET_is_zero (&revoke_dkh)) &&
        (GNUNET_OK !=
         revoke_denomination (&revoke_dkh)) )
   {
@@ -1387,7 +1404,7 @@ main (int argc,
                                         "time",
                                         "TIMESTAMP",
                                         "pretend it is a different time for 
the update",
-                                        &now),
+                                        &now_tmp),
     GNUNET_GETOPT_OPTION_END
   };
 
@@ -1395,7 +1412,7 @@ main (int argc,
                  GNUNET_log_setup ("taler-exchange-keyup",
                                    "WARNING",
                                    NULL));
-  now = GNUNET_TIME_absolute_get ();
+  now = now_tmp = GNUNET_TIME_absolute_get ();
   if (GNUNET_OK !=
       GNUNET_PROGRAM_run (argc, argv,
                         "taler-exchange-keyup",
diff --git a/src/exchange-tools/taler-wire.c b/src/exchange-tools/taler-wire.c
index ee7eeb8c..c07f1f64 100644
--- a/src/exchange-tools/taler-wire.c
+++ b/src/exchange-tools/taler-wire.c
@@ -26,8 +26,8 @@
 
 #include <platform.h>
 #include <gnunet/gnunet_util_lib.h>
-#include <taler/taler_util.h>
-#include <taler/taler_wire_lib.h>
+#include "taler_util.h"
+#include "taler_wire_lib.h"
 
 /**
  * If set to GNUNET_YES, then we'll ask the bank for a list
diff --git a/src/exchange/taler-exchange-aggregator.c 
b/src/exchange/taler-exchange-aggregator.c
index af0c8e6c..299b892f 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -624,13 +624,11 @@ refund_by_coin_cb (void *cls,
 
   /* TODO: potential optimization: include these conditions
      in the SELECT! */
-  if (0 != memcmp (merchant_pub,
-                  &au->merchant_pub,
-                  sizeof (struct TALER_MerchantPublicKeyP)))
+  if (0 != GNUNET_memcmp (merchant_pub,
+                          &au->merchant_pub))
     return GNUNET_OK; /* different merchant */
-  if (0 != memcmp (h_contract,
-                  au->h_contract,
-                  sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (h_contract,
+                          au->h_contract))
     return GNUNET_OK; /* different contract */
   if (GNUNET_OK !=
       TALER_amount_subtract (&au->total_amount,
@@ -795,10 +793,8 @@ aggregate_cb (void *cls,
   struct TALER_Amount delta;
   enum GNUNET_DB_QueryStatus qs;
 
-  GNUNET_break (0 ==
-                memcmp (&au->merchant_pub,
-                        merchant_pub,
-                        sizeof (struct TALER_MerchantPublicKeyP)));
+  GNUNET_break (0 == GNUNET_memcmp (&au->merchant_pub,
+                                    merchant_pub));
   /* compute contribution of this coin after fees */
   if (GNUNET_SYSERR ==
       TALER_amount_subtract (&delta,
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index 4813f921..8f86bf79 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -146,6 +146,12 @@ handle_mhd_completion_callback (void *cls,
     return;
   TEH_PARSE_post_cleanup_callback (*con_cls);
   *con_cls = NULL;
+  /* check that we didn't leave any transactions hanging */
+  /* NOTE: In high-performance production, we might want to
+     remove this. */
+  TEH_plugin->preflight (TEH_plugin->cls,
+                         TEH_plugin->get_session (TEH_plugin->cls));
+
 }
 
 
diff --git a/src/exchange/taler-exchange-httpd_db.c 
b/src/exchange/taler-exchange-httpd_db.c
index 579f0620..1f47f8e1 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -87,9 +87,9 @@ TEH_DB_know_coin_transaction (void *cls,
 int
 TEH_DB_run_transaction (struct MHD_Connection *connection,
                         const char *name,
-                       int *mhd_ret,
-                       TEH_DB_TransactionCallback cb,
-                       void *cb_cls)
+                        int *mhd_ret,
+                        TEH_DB_TransactionCallback cb,
+                        void *cb_cls)
 {
   struct TALER_EXCHANGEDB_Session *session;
 
@@ -100,7 +100,7 @@ TEH_DB_run_transaction (struct MHD_Connection *connection,
     GNUNET_break (0);
     if (NULL != mhd_ret)
       *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
-                                                      
TALER_EC_DB_SETUP_FAILED);
+                                                       
TALER_EC_DB_SETUP_FAILED);
     return GNUNET_SYSERR;
   }
   TEH_plugin->preflight (TEH_plugin->cls,
@@ -110,23 +110,23 @@ TEH_DB_run_transaction (struct MHD_Connection *connection,
     enum GNUNET_DB_QueryStatus qs;
 
     if (GNUNET_OK !=
-       TEH_plugin->start (TEH_plugin->cls,
-                          session,
+        TEH_plugin->start (TEH_plugin->cls,
+                           session,
                            name))
     {
       GNUNET_break (0);
       if (NULL != mhd_ret)
-       *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
-                                                        
TALER_EC_DB_START_FAILED);
+        *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
+                                                         
TALER_EC_DB_START_FAILED);
       return GNUNET_SYSERR;
     }
     qs = cb (cb_cls,
-            connection,
-            session,
-            mhd_ret);
+             connection,
+             session,
+             mhd_ret);
     if (0 > qs)
       TEH_plugin->rollback (TEH_plugin->cls,
-                           session);
+                            session);
     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
       return GNUNET_SYSERR;
     if (0 <= qs)
@@ -135,13 +135,13 @@ TEH_DB_run_transaction (struct MHD_Connection *connection,
     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     {
       if (NULL != mhd_ret)
-       *mhd_ret = TEH_RESPONSE_reply_commit_error (connection,
-                                                   
TALER_EC_DB_COMMIT_FAILED_HARD);
+        *mhd_ret = TEH_RESPONSE_reply_commit_error (connection,
+                                                    
TALER_EC_DB_COMMIT_FAILED_HARD);
       return GNUNET_SYSERR;
     }
     /* make sure callback did not violate invariants! */
     GNUNET_assert ( (NULL == mhd_ret) ||
-                   (-1 == *mhd_ret) );
+                    (-1 == *mhd_ret) );
     if (0 <= qs)
       return GNUNET_OK;
   }
diff --git a/src/exchange/taler-exchange-httpd_deposit.c 
b/src/exchange/taler-exchange-httpd_deposit.c
index 3e91218c..5a1bf496 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -130,9 +130,9 @@ struct DepositContext
  */
 static enum GNUNET_DB_QueryStatus
 deposit_transaction (void *cls,
-                    struct MHD_Connection *connection,
-                    struct TALER_EXCHANGEDB_Session *session,
-                    int *mhd_ret)
+                     struct MHD_Connection *connection,
+                     struct TALER_EXCHANGEDB_Session *session,
+                     int *mhd_ret)
 {
   struct DepositContext *dc = cls;
   const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
@@ -141,8 +141,8 @@ deposit_transaction (void *cls,
   enum GNUNET_DB_QueryStatus qs;
 
   qs = TEH_plugin->have_deposit (TEH_plugin->cls,
-                                session,
-                                deposit,
+                                 session,
+                                 deposit,
                                  GNUNET_YES /* check refund deadline */);
   if (qs < 0)
   {
@@ -159,19 +159,19 @@ deposit_transaction (void *cls,
     struct TALER_Amount amount_without_fee;
 
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-               "/deposit replay, accepting again!\n");
+                "/deposit replay, accepting again!\n");
     GNUNET_assert (GNUNET_OK ==
                    TALER_amount_subtract (&amount_without_fee,
                                           &deposit->amount_with_fee,
                                           &deposit->deposit_fee));
     *mhd_ret = reply_deposit_success (connection,
-                                     &deposit->coin.coin_pub,
-                                     &deposit->h_wire,
-                                     &deposit->h_contract_terms,
-                                     deposit->timestamp,
-                                     deposit->refund_deadline,
-                                     &deposit->merchant_pub,
-                                     &amount_without_fee);
+                                      &deposit->coin.coin_pub,
+                                      &deposit->h_wire,
+                                      &deposit->h_contract_terms,
+                                      deposit->timestamp,
+                                      deposit->refund_deadline,
+                                      &deposit->merchant_pub,
+                                      &amount_without_fee);
     /* Treat as 'hard' DB error as we want to rollback and
        never try again. */
     return GNUNET_DB_STATUS_HARD_ERROR;
@@ -184,13 +184,13 @@ deposit_transaction (void *cls,
                                           session,
                                           &deposit->coin.coin_pub,
                                           GNUNET_NO,
-                                         &tl);
+                                          &tl);
   if (0 > qs)
     return qs;
   if (GNUNET_OK !=
       TEH_DB_calculate_transaction_list_totals (tl,
-                                               &spent,
-                                               &spent))
+                                                &spent,
+                                                &spent))
   {
     TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
                                             tl);
@@ -239,14 +239,14 @@ deposit_transaction (void *cls,
  */
 static int
 verify_and_execute_deposit (struct MHD_Connection *connection,
-                           const struct TALER_EXCHANGEDB_Deposit *deposit)
+                            const struct TALER_EXCHANGEDB_Deposit *deposit)
 {
   struct TALER_DepositRequestPS dr;
   int mhd_ret;
   struct TALER_Amount amount_without_fee;
   struct DepositContext dc;
   struct TEH_KS_StateHandle *mks;
-  struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+  const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
 
   /* check signature */
   dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
@@ -269,12 +269,12 @@ verify_and_execute_deposit (struct MHD_Connection 
*connection,
   {
     TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
     return TEH_RESPONSE_reply_signature_invalid (connection,
-                                                
TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID,
+                                                 
TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID,
                                                  "coin_sig");
   }
 
   /* check denomination */
-  mks = TEH_KS_acquire ();
+  mks = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == mks)
   {
     TALER_LOG_ERROR ("Lacking keys to operate\n");
@@ -282,9 +282,9 @@ verify_and_execute_deposit (struct MHD_Connection 
*connection,
                                               
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
                                               "no keys");
   }
-  dki = TEH_KS_denomination_key_lookup (mks,
-                                        &deposit->coin.denom_pub,
-                                       TEH_KS_DKU_DEPOSIT);
+  dki = TEH_KS_denomination_key_lookup_by_hash (mks,
+                                                &deposit->coin.denom_pub_hash,
+                                                TEH_KS_DKU_DEPOSIT);
   if (NULL == dki)
   {
     TEH_KS_release (mks);
@@ -300,9 +300,9 @@ verify_and_execute_deposit (struct MHD_Connection 
*connection,
   if (GNUNET_OK !=
       TEH_DB_run_transaction (connection,
                               "execute deposit",
-                             &mhd_ret,
-                             &deposit_transaction,
-                             &dc))
+                              &mhd_ret,
+                              &deposit_transaction,
+                              &dc))
     return mhd_ret;
 
   /* generate regular response */
@@ -311,13 +311,13 @@ verify_and_execute_deposit (struct MHD_Connection 
*connection,
                                         &deposit->amount_with_fee,
                                         &deposit->deposit_fee));
   return reply_deposit_success (connection,
-                               &deposit->coin.coin_pub,
-                               &deposit->h_wire,
-                               &deposit->h_contract_terms,
-                               deposit->timestamp,
-                               deposit->refund_deadline,
-                               &deposit->merchant_pub,
-                               &amount_without_fee);
+                                &deposit->coin.coin_pub,
+                                &deposit->h_wire,
+                                &deposit->h_contract_terms,
+                                deposit->timestamp,
+                                deposit->refund_deadline,
+                                &deposit->merchant_pub,
+                                &amount_without_fee);
 }
 
 
@@ -392,7 +392,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
   struct GNUNET_JSON_Specification spec[] = {
     GNUNET_JSON_spec_json ("wire", &wire),
     TALER_JSON_spec_amount ("contribution", &deposit.amount_with_fee),
-    TALER_JSON_spec_denomination_public_key ("denom_pub", 
&deposit.coin.denom_pub),
+    GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", 
&deposit.coin.denom_pub_hash),
     TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
     GNUNET_JSON_spec_fixed_auto ("coin_pub", &deposit.coin.coin_pub),
     GNUNET_JSON_spec_fixed_auto ("merchant_pub", &deposit.merchant_pub),
@@ -467,9 +467,8 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
                                           
TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON,
                                            "wire");
   }
-  if (0 != memcmp (&deposit.h_wire,
-                  &my_h_wire,
-                  sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (&deposit.h_wire,
+                          &my_h_wire))
   {
     /* Client hashed contract differently than we did, reject */
     GNUNET_JSON_parse_free (spec);
@@ -479,7 +478,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
   }
 
   /* check denomination exists and is valid */
-  key_state = TEH_KS_acquire ();
+  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == key_state)
   {
     TALER_LOG_ERROR ("Lacking keys to operate\n");
@@ -488,9 +487,9 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
                                               
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
                                               "no keys");
   }
-  dki = TEH_KS_denomination_key_lookup (key_state,
-                                        &deposit.coin.denom_pub,
-                                       TEH_KS_DKU_DEPOSIT);
+  dki = TEH_KS_denomination_key_lookup_by_hash (key_state,
+                                                &deposit.coin.denom_pub_hash,
+                                                TEH_KS_DKU_DEPOSIT);
   if (NULL == dki)
   {
     /* FIXME: #3887: if DK was revoked, we might want to give a 403 and not a 
404! */
@@ -505,7 +504,8 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
                      &dki->issue.properties.fee_deposit);
   /* check coin signature */
   if (GNUNET_YES !=
-      TALER_test_coin_valid (&deposit.coin))
+      TALER_test_coin_valid (&deposit.coin,
+                             &dki->denom_pub))
   {
     TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
     TEH_KS_release (key_state);
diff --git a/src/exchange/taler-exchange-httpd_keystate.c 
b/src/exchange/taler-exchange-httpd_keystate.c
index b15749ca..a452a124 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -39,7 +39,7 @@
  * release version, and the format is NOT the same that semantic
  * versioning uses either.
  */
-#define TALER_PROTOCOL_VERSION "2:0:0"
+#define TALER_PROTOCOL_VERSION "3:0:0"
 
 
 /**
@@ -211,6 +211,10 @@ struct ResponseFactoryContext
    */
   unsigned int denomkey_array_length;
 
+  /**
+   * Time stamp used as "now".
+   */
+  struct GNUNET_TIME_Absolute now;
 };
 
 
@@ -670,7 +674,7 @@ add_denomination_transaction (void *cls,
 
   qs = TEH_plugin->get_denomination_info (TEH_plugin->cls,
                                          session,
-                                         &dki->denom_pub,
+                                         &dki->issue.properties.denom_hash,
                                          &issue_exists);
   if (0 > qs)
     return qs;
@@ -700,7 +704,6 @@ reload_keys_denom_iter (void *cls,
 {
   struct ResponseFactoryContext *rfc = cls;
   struct TEH_KS_StateHandle *key_state = rfc->key_state;
-  struct GNUNET_TIME_Absolute now;
   struct GNUNET_TIME_Absolute start;
   struct GNUNET_TIME_Absolute horizon;
   struct GNUNET_TIME_Absolute expire_deposit;
@@ -709,18 +712,16 @@ reload_keys_denom_iter (void *cls,
               "Loading denomination key `%s' (%s)\n",
               alias,
              GNUNET_h2s (&dki->issue.properties.denom_hash));
-  now = GNUNET_TIME_absolute_get ();
   expire_deposit = GNUNET_TIME_absolute_ntoh 
(dki->issue.properties.expire_deposit);
-  if (expire_deposit.abs_value_us < now.abs_value_us)
+  if (expire_deposit.abs_value_us < rfc->now.abs_value_us)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Skipping expired denomination key `%s'\n",
                 alias);
     return GNUNET_OK;
   }
-  if (0 != memcmp (&dki->issue.properties.master,
-                   &TEH_master_public_key,
-                   sizeof (struct TALER_MasterPublicKeyP)))
+  if (0 != GNUNET_memcmp (&dki->issue.properties.master,
+                          &TEH_master_public_key))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Master key in denomination key file `%s' does not match! 
Skipping it.\n",
@@ -728,7 +729,8 @@ reload_keys_denom_iter (void *cls,
     return GNUNET_OK;
   }
 
-  horizon = GNUNET_TIME_relative_to_absolute 
(TALER_EXCHANGE_conf_duration_provide ());
+  horizon = GNUNET_TIME_absolute_add (rfc->now,
+                                      TALER_EXCHANGE_conf_duration_provide ());
   start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
   if (start.abs_value_us > horizon.abs_value_us)
   {
@@ -787,7 +789,7 @@ revocations_iter (void *cls,
   struct TEH_KS_StateHandle *key_state = rfc->key_state;
   struct AddRevocationContext arc;
   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
-  
+
   dki = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map,
                                           denom_hash);
   if (NULL == dki)
@@ -900,9 +902,8 @@ reload_keys_sign_iter (void *cls,
     return GNUNET_OK;
   }
 
-  if (0 != memcmp (&ski->issue.master_public_key,
-                   &TEH_master_public_key,
-                   sizeof (struct TALER_MasterPublicKeyP)))
+  if (0 != GNUNET_memcmp (&ski->issue.master_public_key,
+                          &TEH_master_public_key))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Master key in signing key file `%s' does not match! Skipping 
it.\n",
@@ -1492,6 +1493,13 @@ reload_public_denoms_cb (void *cls,
   struct ResponseFactoryContext *rfc = cls;
   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation dki;
 
+  if (rfc->now.abs_value_us > GNUNET_TIME_absolute_ntoh
+    (issue->properties.expire_legal).abs_value_us)
+  {
+    /* Expired key, discard.  */
+    return;
+  }
+
   if (NULL !=
       GNUNET_CONTAINER_multihashmap_get (rfc->key_state->denomkey_map,
                                          &issue->properties.denom_hash))
@@ -1524,7 +1532,7 @@ reload_public_denoms_cb (void *cls,
  * @return NULL on error (usually pretty fatal...)
  */
 static struct TEH_KS_StateHandle *
-make_fresh_key_state ()
+make_fresh_key_state (struct GNUNET_TIME_Absolute now)
 {
   struct TEH_KS_StateHandle *key_state;
   struct ResponseFactoryContext rfc;
@@ -1551,6 +1559,7 @@ make_fresh_key_state ()
 
   key_state = GNUNET_new (struct TEH_KS_StateHandle);
   rfc.key_state = key_state;
+  rfc.now = now;
   key_state->min_dk_expire = GNUNET_TIME_UNIT_FOREVER_ABS;
   key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32,
                                                                   GNUNET_NO);
@@ -1604,7 +1613,7 @@ make_fresh_key_state ()
     json_decref (rfc.sign_keys_array);
     return NULL;
   }
-  
+
   /* Initialize `current_sign_key_issue` and `rfc.sign_keys_array` */
   TALER_EXCHANGEDB_signing_keys_iterate (TEH_exchange_directory,
                                          &reload_keys_sign_iter,
@@ -1774,9 +1783,9 @@ TEH_KS_release_ (const char *location,
  * @return the key state, NULL on error (usually pretty fatal)
  */
 struct TEH_KS_StateHandle *
-TEH_KS_acquire_ (const char *location)
+TEH_KS_acquire_ (struct GNUNET_TIME_Absolute now,
+                 const char *location)
 {
-  struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
   struct TEH_KS_StateHandle *key_state;
   unsigned int rcd;
 
@@ -1795,7 +1804,7 @@ TEH_KS_acquire_ (const char *location)
   }
   if (NULL == internal_key_state)
   {
-    internal_key_state = make_fresh_key_state ();
+    internal_key_state = make_fresh_key_state (now);
     /* bump RC by 1 if we released internal_key_state above */
     if (NULL == internal_key_state)
     {
@@ -2041,7 +2050,7 @@ TEH_KS_loop (void)
     }
     /* This will re-initialize 'internal_key_state' with
        an initial refcnt of 1 */
-    if (NULL == TEH_KS_acquire ())
+    if (NULL == TEH_KS_acquire (GNUNET_TIME_absolute_get ()))
     {
       ret = GNUNET_SYSERR;
       break;
@@ -2133,7 +2142,7 @@ TEH_KS_sign (const struct 
GNUNET_CRYPTO_EccSignaturePurpose *purpose,
 {
   struct TEH_KS_StateHandle *key_state;
 
-  key_state = TEH_KS_acquire ();
+  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == key_state)
   {
     /* This *can* happen if the exchange's keys are
@@ -2195,34 +2204,57 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
 {
   struct TEH_KS_StateHandle *key_state;
   int ret;
-  const char *have;
+  const char *have_cherrypick;
+  const char *have_fakenow;
   struct GNUNET_TIME_Absolute last_issue_date;
+  struct GNUNET_TIME_Absolute now;
   const struct KeysResponseData *krd;
 
-  have = MHD_lookup_connection_value (connection,
-                                     MHD_GET_ARGUMENT_KIND,
-                                     "last_issue_date");
-  if (NULL != have)
+  have_cherrypick = MHD_lookup_connection_value (connection,
+                                                 MHD_GET_ARGUMENT_KIND,
+                                                 "last_issue_date");
+  if (NULL != have_cherrypick)
   {
-    unsigned long long haven;
+    unsigned long long cherrypickn;
 
     if (1 !=
-       sscanf (have,
+       sscanf (have_cherrypick,
                "%llu",
-               &haven))
+               &cherrypickn))
     {
       GNUNET_break_op (0);
       return TEH_RESPONSE_reply_arg_invalid (connection,
                                             TALER_EC_KEYS_HAVE_NOT_NUMERIC,
-                                            "have");
+                                            "last_issue_date");
     }
-    last_issue_date.abs_value_us = (uint64_t) haven * 1000000LLU;
+    last_issue_date.abs_value_us = (uint64_t) cherrypickn * 1000000LLU;
   }
   else
   {
     last_issue_date.abs_value_us = 0LLU;
   }
-  key_state = TEH_KS_acquire ();
+  now = GNUNET_TIME_absolute_get ();
+  have_fakenow = MHD_lookup_connection_value (connection,
+                                              MHD_GET_ARGUMENT_KIND,
+                                              "now");
+  if (NULL != have_fakenow)
+  {
+    unsigned long long fakenown;
+
+    if (1 !=
+       sscanf (have_fakenow,
+               "%llu",
+               &fakenown))
+    {
+      GNUNET_break_op (0);
+      return TEH_RESPONSE_reply_arg_invalid (connection,
+                                            TALER_EC_KEYS_HAVE_NOT_NUMERIC,
+                                            "now");
+    }
+    now.abs_value_us = (uint64_t) fakenown * 1000000LLU;
+  }
+
+  key_state = TEH_KS_acquire (now);
   if (NULL == key_state)
   {
     TALER_LOG_ERROR ("Lacking keys to operate\n");
diff --git a/src/exchange/taler-exchange-httpd_keystate.h 
b/src/exchange/taler-exchange-httpd_keystate.h
index 29e8cd50..c9b98230 100644
--- a/src/exchange/taler-exchange-httpd_keystate.h
+++ b/src/exchange/taler-exchange-httpd_keystate.h
@@ -45,7 +45,8 @@ struct TEH_KS_StateHandle;
  * @return the key state, NULL on error (usually pretty fatal)
  */
 struct TEH_KS_StateHandle *
-TEH_KS_acquire_ (const char *location);
+TEH_KS_acquire_ (struct GNUNET_TIME_Absolute now,
+                 const char *location);
 
 
 /**
@@ -64,9 +65,11 @@ TEH_KS_release_ (const char *location,
  * For every call to #TEH_KS_acquire(), a matching call
  * to #TEH_KS_release() must be made.
  *
+ * @param now current time snapshot; either true, or given by the
+ *        client via the "now" URL parameter of "/keys".
  * @return the key state
  */
-#define TEH_KS_acquire(void) TEH_KS_acquire_(__FUNCTION__)
+#define TEH_KS_acquire(now) TEH_KS_acquire_(now, __FUNCTION__)
 
 
 /**
@@ -124,7 +127,7 @@ enum TEH_KS_DenominationKeyUse {
 struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
 TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
                                 const struct TALER_DenominationPublicKey 
*denom_pub,
-                               enum TEH_KS_DenominationKeyUse use);
+                                enum TEH_KS_DenominationKeyUse use);
 
 
 /**
diff --git a/src/exchange/taler-exchange-httpd_parsing.c 
b/src/exchange/taler-exchange-httpd_parsing.c
index 4d7b5ab6..2a9f7a5a 100644
--- a/src/exchange/taler-exchange-httpd_parsing.c
+++ b/src/exchange/taler-exchange-httpd_parsing.c
@@ -70,6 +70,7 @@ TEH_PARSE_post_json (struct MHD_Connection *connection,
   enum GNUNET_JSON_PostResult pr;
 
   pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+                                connection,
                                 con_cls,
                                 upload_data,
                                 upload_data_size,
diff --git a/src/exchange/taler-exchange-httpd_payback.c 
b/src/exchange/taler-exchange-httpd_payback.c
index 877a3ce2..06181519 100644
--- a/src/exchange/taler-exchange-httpd_payback.c
+++ b/src/exchange/taler-exchange-httpd_payback.c
@@ -318,7 +318,7 @@ verify_and_execute_payback (struct MHD_Connection 
*connection,
   int mhd_ret;
 
   /* check denomination exists and is in payback mode */
-  key_state = TEH_KS_acquire ();
+  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == key_state)
   {
     TALER_LOG_ERROR ("Lacking keys to operate\n");
@@ -326,9 +326,9 @@ verify_and_execute_payback (struct MHD_Connection 
*connection,
                                               
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
                                               "no keys");
   }
-  dki = TEH_KS_denomination_key_lookup (key_state,
-                                        &coin->denom_pub,
-                                       TEH_KS_DKU_PAYBACK);
+  dki = TEH_KS_denomination_key_lookup_by_hash (key_state,
+                                                &coin->denom_pub_hash,
+                                                TEH_KS_DKU_PAYBACK);
   if (NULL == dki)
   {
     TEH_KS_release (key_state);
@@ -342,7 +342,8 @@ verify_and_execute_payback (struct MHD_Connection 
*connection,
 
   /* check denomination signature */
   if (GNUNET_YES !=
-      TALER_test_coin_valid (coin))
+      TALER_test_coin_valid (coin,
+                             &dki->denom_pub))
   {
     TALER_LOG_WARNING ("Invalid coin passed for /payback\n");
     TEH_KS_release (key_state);
@@ -358,8 +359,6 @@ verify_and_execute_payback (struct MHD_Connection 
*connection,
   pr.h_denom_pub = dki->issue.properties.denom_hash;
   pr.coin_blind = *coin_bks;
 
-  TEH_KS_release (key_state);
-
   if (GNUNET_OK !=
       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_PAYBACK,
                                   &pr.purpose,
@@ -367,6 +366,7 @@ verify_and_execute_payback (struct MHD_Connection 
*connection,
                                   &coin->coin_pub.eddsa_pub))
   {
     TALER_LOG_WARNING ("Invalid signature on /payback request\n");
+    TEH_KS_release (key_state);
     return TEH_RESPONSE_reply_signature_invalid (connection,
                                                 
TALER_EC_PAYBACK_SIGNATURE_INVALID,
                                                  "coin_sig");
@@ -378,15 +378,18 @@ verify_and_execute_payback (struct MHD_Connection 
*connection,
   if (GNUNET_YES !=
       GNUNET_CRYPTO_rsa_blind (&c_hash,
                                &coin_bks->bks,
-                               coin->denom_pub.rsa_public_key,
+                               dki->denom_pub.rsa_public_key,
                                &coin_ev,
                                &coin_ev_size))
   {
     GNUNET_break (0);
+    TEH_KS_release (key_state);
+
     return TEH_RESPONSE_reply_internal_error (connection,
                                               TALER_EC_PAYBACK_BLINDING_FAILED,
                                               "coin_bks");
   }
+  TEH_KS_release (key_state);
   GNUNET_CRYPTO_hash (coin_ev,
                       coin_ev_size,
                       &pc.h_blind);
@@ -454,8 +457,8 @@ TEH_PAYBACK_handler_payback (struct TEH_RequestHandler *rh,
   struct TALER_DenominationBlindingKeyP coin_bks;
   struct TALER_CoinSpendSignatureP coin_sig;
   struct GNUNET_JSON_Specification spec[] = {
-    TALER_JSON_spec_denomination_public_key ("denom_pub",
-                                             &coin.denom_pub),
+    GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
+                                 &coin.denom_pub_hash),
     TALER_JSON_spec_denomination_signature ("denom_sig",
                                             &coin.denom_sig),
     GNUNET_JSON_spec_fixed_auto ("coin_pub",
diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c 
b/src/exchange/taler-exchange-httpd_refresh_melt.c
index 81a8aca9..1b8e04a0 100644
--- a/src/exchange/taler-exchange-httpd_refresh_melt.c
+++ b/src/exchange/taler-exchange-httpd_refresh_melt.c
@@ -412,8 +412,8 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler 
*rh,
                                  &rmc.refresh_session.coin.coin_pub),
     TALER_JSON_spec_denomination_signature ("denom_sig",
                                             
&rmc.refresh_session.coin.denom_sig),
-    TALER_JSON_spec_denomination_public_key ("denom_pub",
-                                             
&rmc.refresh_session.coin.denom_pub),
+    GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
+                                 &rmc.refresh_session.coin.denom_pub_hash),
     GNUNET_JSON_spec_fixed_auto ("confirm_sig",
                                  &rmc.refresh_session.coin_sig),
     TALER_JSON_spec_amount ("value_with_fee",
@@ -444,18 +444,7 @@ TEH_REFRESH_handler_refresh_melt (struct 
TEH_RequestHandler *rh,
   if (GNUNET_OK != res)
     return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
 
-  if (GNUNET_OK !=
-      TALER_test_coin_valid (&rmc.refresh_session.coin))
-  {
-    GNUNET_break_op (0);
-    GNUNET_JSON_parse_free (spec);
-    return TEH_RESPONSE_reply_signature_invalid (connection,
-                                                 
TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID,
-                                                 "denom_sig");
-  }
-
-  /* run actual logic, now that the request was parsed */
-  key_state = TEH_KS_acquire ();
+  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == key_state)
   {
     TALER_LOG_ERROR ("Lacking keys to operate\n");
@@ -464,9 +453,9 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler 
*rh,
                                              "no keys");
     goto cleanup;
   }
-  rmc.dki = TEH_KS_denomination_key_lookup (key_state,
-                                            
&rmc.refresh_session.coin.denom_pub,
-                                            TEH_KS_DKU_DEPOSIT);
+  rmc.dki = TEH_KS_denomination_key_lookup_by_hash (key_state,
+                                                    
&rmc.refresh_session.coin.denom_pub_hash,
+                                                    TEH_KS_DKU_DEPOSIT);
   if (NULL == rmc.dki)
   {
     TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n");
@@ -476,6 +465,20 @@ TEH_REFRESH_handler_refresh_melt (struct 
TEH_RequestHandler *rh,
     goto cleanup;
   }
 
+  if (GNUNET_OK !=
+      TALER_test_coin_valid (&rmc.refresh_session.coin,
+                             &rmc.dki->denom_pub))
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    TEH_KS_release (key_state);
+    return TEH_RESPONSE_reply_signature_invalid (connection,
+                                                 
TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID,
+                                                 "denom_sig");
+  }
+
+  /* run actual logic, now that the request was parsed */
+
   /* make sure coin is 'known' in database */
   {
     struct TEH_DB_KnowCoinContext kcc;
@@ -502,11 +505,6 @@ TEH_REFRESH_handler_refresh_melt (struct 
TEH_RequestHandler *rh,
     TEH_KS_release (key_state);
     key_state = NULL;
   }
-  if (NULL != rmc.refresh_session.coin.denom_pub.rsa_public_key)
-  {
-    GNUNET_CRYPTO_rsa_public_key_free 
(rmc.refresh_session.coin.denom_pub.rsa_public_key);
-    rmc.refresh_session.coin.denom_pub.rsa_public_key = NULL;
-  }
   if (NULL != rmc.refresh_session.coin.denom_sig.rsa_signature)
   {
     GNUNET_CRYPTO_rsa_signature_free 
(rmc.refresh_session.coin.denom_sig.rsa_signature);
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c 
b/src/exchange/taler-exchange-httpd_refresh_reveal.c
index 6eaa286d..25de5f1f 100644
--- a/src/exchange/taler-exchange-httpd_refresh_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c
@@ -265,7 +265,6 @@ static void
 free_refresh_melt (struct TALER_EXCHANGEDB_RefreshMelt *refresh_melt)
 {
   GNUNET_CRYPTO_rsa_signature_free 
(refresh_melt->session.coin.denom_sig.rsa_signature);
-  GNUNET_CRYPTO_rsa_public_key_free 
(refresh_melt->session.coin.denom_pub.rsa_public_key);
 }
 
 
@@ -399,9 +398,8 @@ refresh_reveal_transaction (void *cls,
     }
 
     /* Verify rc_expected matches rc */
-    if (0 != memcmp (&rctx->rc,
-                     &rc_expected,
-                     sizeof (struct TALER_RefreshCommitmentP)))
+    if (0 != GNUNET_memcmp (&rctx->rc,
+                            &rc_expected))
     {
       GNUNET_break_op (0);
       *mhd_ret = reply_refresh_reveal_missmatch (connection,
@@ -579,7 +577,7 @@ handle_refresh_reveal_json (struct MHD_Connection 
*connection,
     int res;
 
     /* Resolve denomination hashes */
-    key_state = TEH_KS_acquire ();
+    key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
     if (NULL == key_state)
     {
       TALER_LOG_ERROR ("Lacking keys to operate\n");
diff --git a/src/exchange/taler-exchange-httpd_refund.c 
b/src/exchange/taler-exchange-httpd_refund.c
index 86915806..ee6aac1b 100644
--- a/src/exchange/taler-exchange-httpd_refund.c
+++ b/src/exchange/taler-exchange-httpd_refund.c
@@ -331,7 +331,7 @@ refund_transaction (void *cls,
 
   // FIXME: do this outside of transaction function?
   /* Check refund fee matches fee of denomination key! */
-  mks = TEH_KS_acquire ();
+  mks = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == mks)
   {
     TALER_LOG_ERROR ("Lacking keys to operate\n");
@@ -342,9 +342,9 @@ refund_transaction (void *cls,
                                                   "no keys");
     return GNUNET_DB_STATUS_HARD_ERROR;
   }
-  dki = TEH_KS_denomination_key_lookup (mks,
-                                        &dep->coin.denom_pub,
-                                       TEH_KS_DKU_DEPOSIT);
+  dki = TEH_KS_denomination_key_lookup_by_hash (mks,
+                                                &dep->coin.denom_pub_hash,
+                                                TEH_KS_DKU_DEPOSIT);
   if (NULL == dki)
   {
     /* DKI not found, but we do have a coin with this DK in our database;
diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c 
b/src/exchange/taler-exchange-httpd_reserve_withdraw.c
index 1a05326d..c988cde6 100644
--- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c
@@ -116,9 +116,9 @@ struct WithdrawContext
   struct TALER_Amount amount_required;
 
   /**
-   * Denomination public key.
+   * Hash of the denomination public key.
    */
-  struct TALER_DenominationPublicKey denomination_pub;
+  struct GNUNET_HashCode denom_pub_hash;
 
   /**
    * Signature over the request.
@@ -229,7 +229,7 @@ withdraw_transaction (void *cls,
    */
   {
 #define PUBSIZE 80
-    char pub_s[PUBSIZE]; 
+    char pub_s[PUBSIZE];
 
     GNUNET_break
       (NULL != GNUNET_STRINGS_data_to_string (&r.pub,
@@ -312,7 +312,7 @@ withdraw_transaction (void *cls,
 #endif
   TALER_amount_ntoh (&fee_withdraw,
                      &wc->dki->issue.properties.fee_withdraw);
-  wc->collectable.denom_pub = wc->denomination_pub;
+  wc->collectable.denom_pub_hash = wc->denom_pub_hash;
   wc->collectable.amount_with_fee = wc->amount_required;
   wc->collectable.withdraw_fee = fee_withdraw;
   wc->collectable.reserve_pub = wc->wsrd.reserve_pub;
@@ -370,8 +370,8 @@ TEH_RESERVE_handler_reserve_withdraw (struct 
TEH_RequestHandler *rh,
                                  &wc.wsrd.reserve_pub),
     GNUNET_JSON_spec_fixed_auto ("reserve_sig",
                                  &wc.signature),
-    TALER_JSON_spec_denomination_public_key ("denom_pub",
-                                             &wc.denomination_pub),
+    GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
+                                 &wc.denom_pub_hash),
     GNUNET_JSON_spec_end ()
   };
 
@@ -390,7 +390,7 @@ TEH_RESERVE_handler_reserve_withdraw (struct 
TEH_RequestHandler *rh,
   json_decref (root);
   if (GNUNET_OK != res)
     return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
-  wc.key_state = TEH_KS_acquire ();
+  wc.key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
   if (NULL == wc.key_state)
   {
     TALER_LOG_ERROR ("Lacking keys to operate\n");
@@ -399,9 +399,9 @@ TEH_RESERVE_handler_reserve_withdraw (struct 
TEH_RequestHandler *rh,
                                               
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
                                               "no keys");
   }
-  wc.dki = TEH_KS_denomination_key_lookup (wc.key_state,
-                                          &wc.denomination_pub,
-                                          TEH_KS_DKU_WITHDRAW);
+  wc.dki = TEH_KS_denomination_key_lookup_by_hash (wc.key_state,
+                                                   &wc.denom_pub_hash,
+                                                   TEH_KS_DKU_WITHDRAW);
   if (NULL == wc.dki)
   {
     GNUNET_JSON_parse_free (spec);
@@ -435,8 +435,8 @@ TEH_RESERVE_handler_reserve_withdraw (struct 
TEH_RequestHandler *rh,
     = htonl (sizeof (struct TALER_WithdrawRequestPS));
   wc.wsrd.purpose.purpose
     = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
-  GNUNET_CRYPTO_rsa_public_key_hash (wc.denomination_pub.rsa_public_key,
-                                     &wc.wsrd.h_denomination_pub);
+  wc.wsrd.h_denomination_pub
+    = wc.denom_pub_hash;
   GNUNET_CRYPTO_hash (wc.blinded_msg,
                       wc.blinded_msg_len,
                       &wc.wsrd.h_coin_envelope);
diff --git a/src/exchange/taler-exchange-httpd_responses.c 
b/src/exchange/taler-exchange-httpd_responses.c
index 21046ef9..21394337 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -750,7 +750,6 @@ TEH_RESPONSE_compile_reserve_history (const struct 
TALER_EXCHANGEDB_ReserveHisto
       break;
     case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
       {
-       struct GNUNET_HashCode h_denom_pub;
        struct TALER_Amount value;
 
        value = pos->details.withdraw->amount_with_fee;
@@ -771,15 +770,13 @@ TEH_RESPONSE_compile_reserve_history (const struct 
TALER_EXCHANGEDB_ReserveHisto
          }
        }
        ret |= 2;
-       GNUNET_CRYPTO_rsa_public_key_hash 
(pos->details.withdraw->denom_pub.rsa_public_key,
-                                          &h_denom_pub);
        GNUNET_assert (0 ==
                       json_array_append_new (json_history,
                                              json_pack ("{s:s, s:o, s:o, s:o, 
s:o, s:o}",
                                                         "type", "WITHDRAW",
                                                         "reserve_sig", 
GNUNET_JSON_from_data_auto (&pos->details.withdraw->reserve_sig),
                                                         "h_coin_envelope", 
GNUNET_JSON_from_data_auto (&pos->details.withdraw->h_coin_envelope),
-                                                        "h_denom_pub", 
GNUNET_JSON_from_data_auto (&h_denom_pub),
+                                                        "h_denom_pub", 
GNUNET_JSON_from_data_auto (&pos->details.withdraw->denom_pub_hash),
                                                         "withdraw_fee", 
TALER_JSON_from_amount (&pos->details.withdraw->withdraw_fee),
                                                         "amount", 
TALER_JSON_from_amount (&value))));
       }
diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c 
b/src/exchange/taler-exchange-httpd_track_transfer.c
index 429c86f3..1ed62d6c 100644
--- a/src/exchange/taler-exchange-httpd_track_transfer.c
+++ b/src/exchange/taler-exchange-httpd_track_transfer.c
@@ -289,14 +289,12 @@ handle_transaction_data (void *cls,
   }
   else
   {
-    if ( (0 != memcmp (&ctx->merchant_pub,
-                       merchant_pub,
-                       sizeof (struct TALER_MerchantPublicKeyP))) ||
+    if ( (0 != GNUNET_memcmp (&ctx->merchant_pub,
+                              merchant_pub)) ||
          (0 != strcmp (wire_method,
                        ctx->wire_method)) ||
-         (0 != memcmp (&ctx->h_wire,
-                       h_wire,
-                       sizeof (struct GNUNET_HashCode))) )
+         (0 != GNUNET_memcmp (&ctx->h_wire,
+                              h_wire)) )
     {
       GNUNET_break (0);
       ctx->is_valid = GNUNET_SYSERR;
diff --git a/src/exchange/test_taler_exchange_aggregator.c 
b/src/exchange/test_taler_exchange_aggregator.c
index 0ba8152d..c0d3d912 100644
--- a/src/exchange/test_taler_exchange_aggregator.c
+++ b/src/exchange/test_taler_exchange_aggregator.c
@@ -383,7 +383,8 @@ fake_coin (struct TALER_CoinPublicInfo *coin)
 {
   struct GNUNET_HashCode hc;
 
-  coin->denom_pub.rsa_public_key = coin_pub;
+  GNUNET_CRYPTO_rsa_public_key_hash (coin_pub,
+                                     &coin->denom_pub_hash);
   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
                                     &hc);
   coin->denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (coin_pk,
diff --git a/src/exchangedb/exchangedb_denomkeys.c 
b/src/exchangedb/exchangedb_denomkeys.c
index 32955dcc..d9e604eb 100644
--- a/src/exchangedb/exchangedb_denomkeys.c
+++ b/src/exchangedb/exchangedb_denomkeys.c
@@ -200,7 +200,7 @@ TALER_EXCHANGEDB_denomination_key_write (const char 
*filename,
   if (NULL == (fh = GNUNET_DISK_file_open
                (filename,
                 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | 
GNUNET_DISK_OPEN_TRUNCATE,
-                GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
+                GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE | 
GNUNET_DISK_OPEN_FAILIFEXISTS)))
     goto cleanup;
   wsize = sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP);
   if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
diff --git a/src/exchangedb/perf_taler_exchangedb_init.c 
b/src/exchangedb/perf_taler_exchangedb_init.c
index 789aaea0..089536a4 100644
--- a/src/exchangedb/perf_taler_exchangedb_init.c
+++ b/src/exchangedb/perf_taler_exchangedb_init.c
@@ -263,9 +263,7 @@ PERF_TALER_EXCHANGEDB_deposit_init (const struct 
PERF_TALER_EXCHANGEDB_Coin *coi
                                          &deposit_fee));
   {
     deposit->coin.coin_pub = coin->public_info.coin_pub;
-    deposit->coin.denom_pub.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_dup (
-      coin->public_info.denom_pub.rsa_public_key);
-    GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key);
+    deposit->coin.denom_pub_hash = coin->public_info.denom_pub_hash;
     deposit->coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (
       coin->public_info.denom_sig.rsa_signature);
     GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature);
@@ -298,8 +296,6 @@ PERF_TALER_EXCHANGEDB_deposit_copy (const struct 
TALER_EXCHANGEDB_Deposit *depos
   copy = GNUNET_new (struct TALER_EXCHANGEDB_Deposit);
   *copy = *deposit;
   copy->receiver_wire_account = json_incref (deposit->receiver_wire_account);
-  copy->coin.denom_pub.rsa_public_key =
-    GNUNET_CRYPTO_rsa_public_key_dup (deposit->coin.denom_pub.rsa_public_key);
   copy->coin.denom_sig.rsa_signature =
     GNUNET_CRYPTO_rsa_signature_dup (deposit->coin.denom_sig.rsa_signature);
   return copy;
@@ -315,7 +311,6 @@ PERF_TALER_EXCHANGEDB_deposit_free (struct 
TALER_EXCHANGEDB_Deposit *deposit)
 {
   if (NULL == deposit)
     return GNUNET_OK;
-  GNUNET_CRYPTO_rsa_public_key_free (deposit->coin.denom_pub.rsa_public_key);
   GNUNET_CRYPTO_rsa_signature_free (deposit->coin.denom_sig.rsa_signature);
   json_decref (deposit->receiver_wire_account);
   GNUNET_free (deposit);
@@ -350,24 +345,21 @@ PERF_TALER_EXCHANGEDB_coin_init (
   /* public_info */
   GNUNET_CRYPTO_eddsa_key_get_public (&coin->priv,
                                       &coin->public_info.coin_pub.eddsa_pub);
-  coin->public_info.denom_pub.rsa_public_key =
-    GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
+  GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
+                                     &coin->public_info.denom_pub_hash);
   GNUNET_CRYPTO_hash (&coin->public_info.coin_pub,
                       sizeof (struct TALER_CoinSpendPublicKeyP),
                       &hc);
   coin->public_info.denom_sig.rsa_signature =
     GNUNET_CRYPTO_rsa_sign_fdh (dki->denom_priv.rsa_private_key,
                                 &hc);
-  GNUNET_assert (NULL != coin->public_info.denom_pub.rsa_public_key);
   GNUNET_assert (NULL != coin->public_info.denom_sig.rsa_signature);
 
   /* blind */
   coin->blind.sig.rsa_signature =
     GNUNET_CRYPTO_rsa_signature_dup 
(coin->public_info.denom_sig.rsa_signature);
-  coin->blind.denom_pub.rsa_public_key =
-    GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
+  coin->blind.denom_pub_hash = coin->public_info.denom_pub_hash;
   GNUNET_assert (NULL != coin->blind.sig.rsa_signature);
-  GNUNET_assert (NULL != coin->blind.denom_pub.rsa_public_key);
   TALER_amount_ntoh (&coin->blind.amount_with_fee,
                      &dki->issue.properties.value);
   TALER_amount_ntoh (&coin->blind.withdraw_fee,
@@ -396,16 +388,14 @@ PERF_TALER_EXCHANGEDB_coin_copy (const struct 
PERF_TALER_EXCHANGEDB_Coin *coin)
   copy->priv = coin->priv;
   /* public_info */
   copy->public_info.coin_pub = coin->public_info.coin_pub;
-  copy->public_info.denom_pub.rsa_public_key =
-    GNUNET_CRYPTO_rsa_public_key_dup 
(coin->public_info.denom_pub.rsa_public_key);
+  copy->public_info.denom_pub_hash = coin->public_info.denom_pub_hash;
   copy->public_info.denom_sig.rsa_signature =
     GNUNET_CRYPTO_rsa_signature_dup 
(coin->public_info.denom_sig.rsa_signature);
 
   /* blind */
   copy->blind.sig.rsa_signature =
     GNUNET_CRYPTO_rsa_signature_dup (coin->blind.sig.rsa_signature);
-  copy->blind.denom_pub.rsa_public_key =
-    GNUNET_CRYPTO_rsa_public_key_dup (coin->blind.denom_pub.rsa_public_key);
+  copy->blind.denom_pub_hash = coin->blind.denom_pub_hash;
   copy->blind.amount_with_fee = coin->blind.amount_with_fee;
   copy->blind.withdraw_fee = coin->blind.withdraw_fee;
   copy->blind.reserve_pub = coin->blind.reserve_pub;
@@ -426,10 +416,8 @@ PERF_TALER_EXCHANGEDB_coin_free (struct 
PERF_TALER_EXCHANGEDB_Coin *coin)
 {
   if (NULL == coin)
     return GNUNET_OK;
-  GNUNET_CRYPTO_rsa_public_key_free 
(coin->public_info.denom_pub.rsa_public_key);
   GNUNET_CRYPTO_rsa_signature_free (coin->public_info.denom_sig.rsa_signature);
   GNUNET_CRYPTO_rsa_signature_free (coin->blind.sig.rsa_signature);
-  GNUNET_CRYPTO_rsa_public_key_free (coin->blind.denom_pub.rsa_public_key);
   GNUNET_free (coin);
   return GNUNET_OK;
 }
@@ -475,9 +463,7 @@ PERF_TALER_EXCHANGEDB_refresh_melt_init (struct 
TALER_RefreshCommitmentP *rc,
   melt->session.coin.coin_pub = coin->public_info.coin_pub;
   melt->session.coin.denom_sig.rsa_signature =
     GNUNET_CRYPTO_rsa_signature_dup 
(coin->public_info.denom_sig.rsa_signature);
-  melt->session.coin.denom_pub.rsa_public_key =
-    GNUNET_CRYPTO_rsa_public_key_dup 
(coin->public_info.denom_pub.rsa_public_key);
-  GNUNET_assert (NULL != melt->session.coin.denom_pub.rsa_public_key);
+  melt->session.coin.denom_pub_hash = coin->public_info.denom_pub_hash;
   GNUNET_assert (NULL != melt->session.coin.denom_sig.rsa_signature);
   melt->session.coin_sig = coin_sig;
   melt->session.rc = *rc;
diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c 
b/src/exchangedb/perf_taler_exchangedb_interpreter.c
index cdd5a5fc..6c968410 100644
--- a/src/exchangedb/perf_taler_exchangedb_interpreter.c
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c
@@ -1342,12 +1342,15 @@ interpret (struct 
PERF_TALER_EXCHANGEDB_interpreter_state *state)
           unsigned int denom_index;
           enum GNUNET_DB_QueryStatus qs;
           struct PERF_TALER_EXCHANGEDB_Data *data;
+          struct GNUNET_HashCode hc;
 
           denom_index = 
state->cmd[state->i].details.get_denomination.index_denom;
           data = &state->cmd[denom_index].exposed;
+          GNUNET_CRYPTO_rsa_public_key_hash 
(data->data.dki->denom_pub.rsa_public_key,
+                                             &hc);
           qs = state->plugin->get_denomination_info (state->plugin->cls,
                                                     state->session,
-                                                    &data->data.dki->denom_pub,
+                                                     &hc,
                                                     &data->data.dki->issue);
           GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs);
         }
diff --git a/src/exchangedb/plugin_exchangedb_common.c 
b/src/exchangedb/plugin_exchangedb_common.c
index 26515670..fd2620c7 100644
--- a/src/exchangedb/plugin_exchangedb_common.c
+++ b/src/exchangedb/plugin_exchangedb_common.c
@@ -49,13 +49,11 @@ common_free_reserve_history (void *cls,
     case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
       cbc = rh->details.withdraw;
       GNUNET_CRYPTO_rsa_signature_free (cbc->sig.rsa_signature);
-      GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub.rsa_public_key);
       GNUNET_free (cbc);
       break;
     case TALER_EXCHANGEDB_RO_PAYBACK_COIN:
       payback = rh->details.payback;
       GNUNET_CRYPTO_rsa_signature_free (payback->coin.denom_sig.rsa_signature);
-      GNUNET_CRYPTO_rsa_public_key_free 
(payback->coin.denom_pub.rsa_public_key);
       GNUNET_free (payback);
       break;
     case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
@@ -92,29 +90,21 @@ common_free_coin_transaction_list (void *cls,
     case TALER_EXCHANGEDB_TT_DEPOSIT:
       if (NULL != list->details.deposit->receiver_wire_account)
         json_decref (list->details.deposit->receiver_wire_account);
-      if (NULL != list->details.deposit->coin.denom_pub.rsa_public_key)
-        GNUNET_CRYPTO_rsa_public_key_free 
(list->details.deposit->coin.denom_pub.rsa_public_key);
       if (NULL != list->details.deposit->coin.denom_sig.rsa_signature)
         GNUNET_CRYPTO_rsa_signature_free 
(list->details.deposit->coin.denom_sig.rsa_signature);
       GNUNET_free (list->details.deposit);
       break;
     case TALER_EXCHANGEDB_TT_REFRESH_MELT:
-      if (NULL != list->details.melt->session.coin.denom_pub.rsa_public_key)
-        GNUNET_CRYPTO_rsa_public_key_free 
(list->details.melt->session.coin.denom_pub.rsa_public_key);
       if (NULL != list->details.melt->session.coin.denom_sig.rsa_signature)
         GNUNET_CRYPTO_rsa_signature_free 
(list->details.melt->session.coin.denom_sig.rsa_signature);
       GNUNET_free (list->details.melt);
       break;
     case TALER_EXCHANGEDB_TT_REFUND:
-      if (NULL != list->details.refund->coin.denom_pub.rsa_public_key)
-        GNUNET_CRYPTO_rsa_public_key_free 
(list->details.refund->coin.denom_pub.rsa_public_key);
       if (NULL != list->details.refund->coin.denom_sig.rsa_signature)
         GNUNET_CRYPTO_rsa_signature_free 
(list->details.refund->coin.denom_sig.rsa_signature);
       GNUNET_free (list->details.refund);
       break;
     case TALER_EXCHANGEDB_TT_PAYBACK:
-      if (NULL != list->details.payback->coin.denom_pub.rsa_public_key)
-        GNUNET_CRYPTO_rsa_public_key_free 
(list->details.payback->coin.denom_pub.rsa_public_key);
       if (NULL != list->details.payback->coin.denom_sig.rsa_signature)
         GNUNET_CRYPTO_rsa_signature_free 
(list->details.payback->coin.denom_sig.rsa_signature);
       GNUNET_free (list->details.payback);
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c 
b/src/exchangedb/plugin_exchangedb_postgres.c
index 6aec3711..9dc8eb2f 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -766,7 +766,7 @@ postgres_prepare (PGconn *db_conn)
        make sure /reserve/withdraw requests are idempotent. */
     GNUNET_PQ_make_prepare ("get_withdraw_info",
                             "SELECT"
-                            " denom.denom_pub"
+                            " denom_pub_hash"
                             ",denom_sig"
                             ",reserve_sig"
                             ",reserve_pub"
@@ -790,7 +790,7 @@ postgres_prepare (PGconn *db_conn)
     GNUNET_PQ_make_prepare ("get_reserves_out",
                             "SELECT"
                             " h_blind_ev"
-                            ",denom.denom_pub"
+                            ",denom_pub_hash"
                             ",denom_sig"
                             ",reserve_sig"
                             ",execution_date"
@@ -838,11 +838,9 @@ postgres_prepare (PGconn *db_conn)
        a coin known to the exchange. */
     GNUNET_PQ_make_prepare ("get_known_coin",
                             "SELECT"
-                            " denom.denom_pub"
+                            " denom_pub_hash"
                             ",denom_sig"
                             " FROM known_coins"
-                            "    JOIN denominations denom"
-                            "      USING (denom_pub_hash)"
                             " WHERE coin_pub=$1"
                             " FOR UPDATE;",
                             1),
@@ -876,7 +874,7 @@ postgres_prepare (PGconn *db_conn)
        high-level information about a melt operation */
     GNUNET_PQ_make_prepare ("get_melt",
                             "SELECT"
-                            " denom.denom_pub"
+                            " kc.denom_pub_hash"
                             ",denom.fee_refresh_val"
                             ",denom.fee_refresh_frac"
                             ",denom.fee_refresh_curr"
@@ -1075,11 +1073,9 @@ postgres_prepare (PGconn *db_conn)
                             ",h_contract_terms"
                             ",h_wire"
                             " FROM deposits"
-                            " WHERE ("
-                            "        (coin_pub=$1)"
+                            " WHERE ((coin_pub=$1)"
                             "    AND (merchant_pub=$3)"
-                            "    AND (h_contract_terms=$2)"
-                            " )"
+                            "    AND (h_contract_terms=$2))"
                             " FOR UPDATE;",
                             3),
     /* Fetch deposits with rowid '\geq' the given parameter */
@@ -1520,6 +1516,7 @@ postgres_prepare (PGconn *db_conn)
                             ",coin_sig"
                             ",coin_blind"
                             ",h_blind_ev"
+                            ",coins.denom_pub_hash"
                             ",denoms.denom_pub"
                             ",coins.denom_sig"
                             ",amount_val"
@@ -1528,10 +1525,10 @@ postgres_prepare (PGconn *db_conn)
                             " FROM payback"
                             "    JOIN known_coins coins"
                             "      USING (coin_pub)"
-                            "    JOIN denominations denoms"
-                            "      USING (denom_pub_hash)"
                             "    JOIN reserves_out ro"
                             "      USING (h_blind_ev)"
+                            "    JOIN denominations denoms"
+                            "      ON (coins.denom_pub_hash = 
denoms.denom_pub_hash)"
                             " WHERE payback_uuid>=$1"
                             " ORDER BY payback_uuid ASC;",
                             1),
@@ -1565,13 +1562,11 @@ postgres_prepare (PGconn *db_conn)
                             ",amount_frac"
                             ",amount_curr"
                             ",timestamp"
-                            ",denoms.denom_pub"
+                            ",coins.denom_pub_hash"
                             ",coins.denom_sig"
                             " FROM payback"
                             "    JOIN known_coins coins"
                             "      USING (coin_pub)"
-                            "    JOIN denominations denoms"
-                            "      USING (denom_pub_hash)"
                             "    JOIN reserves_out ro"
                             "      USING (h_blind_ev)"
                             " WHERE ro.reserve_pub=$1"
@@ -1620,13 +1615,11 @@ postgres_prepare (PGconn *db_conn)
                             ",amount_frac"
                             ",amount_curr"
                             ",timestamp"
-                            ",denoms.denom_pub"
+                            ",coins.denom_pub_hash"
                             ",coins.denom_sig"
                             " FROM payback"
                             "    JOIN known_coins coins"
                             "      USING (coin_pub)"
-                            "    JOIN denominations denoms"
-                            "      USING (denom_pub_hash)"
                             "    JOIN reserves_out ro"
                             "      USING (h_blind_ev)"
                             " WHERE payback.coin_pub=$1;",
@@ -1949,20 +1942,19 @@ postgres_insert_denomination_info (void *cls,
  *
  * @param cls the @e cls of this struct with the plugin-specific state
  * @param session connection to use
- * @param denom_pub the public key used for signing coins of this denomination
+ * @param denom_pub_hash hash of the public key used for signing coins of this 
denomination
  * @param[out] issue set to issue information with value, fees and other info 
about the coin
  * @return transaction status code
  */
 static enum GNUNET_DB_QueryStatus
 postgres_get_denomination_info (void *cls,
                                 struct TALER_EXCHANGEDB_Session *session,
-                                const struct TALER_DenominationPublicKey 
*denom_pub,
+                                const struct GNUNET_HashCode *denom_pub_hash,
                                 struct 
TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
 {
   enum GNUNET_DB_QueryStatus qs;
-  struct GNUNET_HashCode dph;
   struct GNUNET_PQ_QueryParam params[] = {
-    GNUNET_PQ_query_param_auto_from_type (&dph),
+    GNUNET_PQ_query_param_auto_from_type (denom_pub_hash),
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_PQ_ResultSpec rs[] = {
@@ -1991,8 +1983,6 @@ postgres_get_denomination_info (void *cls,
     GNUNET_PQ_result_spec_end
   };
 
-  GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
-                                    &dph);
   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
                                                 "denomination_get",
                                                 params,
@@ -2001,8 +1991,7 @@ postgres_get_denomination_info (void *cls,
     return qs;
   issue->properties.purpose.size = htonl (sizeof (struct 
TALER_DenominationKeyValidityPS));
   issue->properties.purpose.purpose = htonl 
(TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
-  GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
-                                     &issue->properties.denom_hash);
+  issue->properties.denom_hash = *denom_pub_hash;
   return qs;
 }
 
@@ -2396,10 +2385,10 @@ postgres_get_withdraw_info (void *cls,
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                         
&collectable->denom_pub.rsa_public_key),
+    GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                          &collectable->denom_pub_hash),
     GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
-                                        &collectable->sig.rsa_signature),
+                                         &collectable->sig.rsa_signature),
     GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
                                          &collectable->reserve_sig),
     GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
@@ -2436,12 +2425,11 @@ postgres_insert_withdraw_info (void *cls,
 {
   struct PostgresClosure *pg = cls;
   struct TALER_EXCHANGEDB_Reserve reserve;
-  struct GNUNET_HashCode denom_pub_hash;
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_TIME_Absolute expiry;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (&collectable->h_coin_envelope),
-    GNUNET_PQ_query_param_auto_from_type (&denom_pub_hash),
+    GNUNET_PQ_query_param_auto_from_type (&collectable->denom_pub_hash),
     GNUNET_PQ_query_param_rsa_signature (collectable->sig.rsa_signature),
     GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_pub),
     GNUNET_PQ_query_param_auto_from_type (&collectable->reserve_sig),
@@ -2453,8 +2441,6 @@ postgres_insert_withdraw_info (void *cls,
 
   now = GNUNET_TIME_absolute_get ();
   (void) GNUNET_TIME_round_abs (&now);
-  GNUNET_CRYPTO_rsa_public_key_hash (collectable->denom_pub.rsa_public_key,
-                                    &denom_pub_hash);
   qs = GNUNET_PQ_eval_prepared_non_select (session->conn,
                                           "insert_withdraw_info",
                                           params);
@@ -2640,8 +2626,8 @@ add_withdraw_coin (void *cls,
       struct GNUNET_PQ_ResultSpec rs[] = {
        GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
                                              &cbc->h_coin_envelope),
-       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                             &cbc->denom_pub.rsa_public_key),
+       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                             &cbc->denom_pub_hash),
        GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
                                             &cbc->sig.rsa_signature),
        GNUNET_PQ_result_spec_auto_from_type ("reserve_sig",
@@ -2694,7 +2680,7 @@ add_payback (void *cls,
     payback = GNUNET_new (struct TALER_EXCHANGEDB_Payback);
     {
       struct GNUNET_PQ_ResultSpec rs[] = {
-       TALER_PQ_result_spec_amount ("amount",
+    TALER_PQ_result_spec_amount ("amount",
                                     &payback->value),
        GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
                                              &payback->coin.coin_pub),
@@ -2704,10 +2690,10 @@ add_payback (void *cls,
                                              &payback->coin_sig),
        TALER_PQ_result_spec_absolute_time ("timestamp",
                                             &payback->timestamp),
-       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                             
&payback->coin.denom_pub.rsa_public_key),
+       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                          &payback->coin.denom_pub_hash),
        GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
-                                            
&payback->coin.denom_sig.rsa_signature),
+                                         
&payback->coin.denom_sig.rsa_signature),
        GNUNET_PQ_result_spec_end
       };
 
@@ -2893,15 +2879,15 @@ postgres_have_deposit (void *cls,
   struct TALER_EXCHANGEDB_Deposit deposit2;
   struct GNUNET_PQ_ResultSpec rs[] = {
     TALER_PQ_result_spec_amount ("amount_with_fee",
-                                &deposit2.amount_with_fee),
+                                 &deposit2.amount_with_fee),
     TALER_PQ_result_spec_absolute_time ("timestamp",
-                                        &deposit2.timestamp),
+                                        &deposit2.timestamp),
     TALER_PQ_result_spec_absolute_time ("refund_deadline",
-                                        &deposit2.refund_deadline),
+                                        &deposit2.refund_deadline),
     TALER_PQ_result_spec_absolute_time ("wire_deadline",
-                                        &deposit2.wire_deadline),
+                                        &deposit2.wire_deadline),
     GNUNET_PQ_result_spec_auto_from_type ("h_wire",
-                                         &deposit2.h_wire),
+                                          &deposit2.h_wire),
     GNUNET_PQ_result_spec_end
   };
   enum GNUNET_DB_QueryStatus qs;
@@ -2910,9 +2896,9 @@ postgres_have_deposit (void *cls,
               "Getting deposits for coin %s\n",
               TALER_B2S (&deposit->coin.coin_pub));
   qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
-                                                "get_deposit",
-                                                params,
-                                                rs);
+                                                 "get_deposit",
+                                                 params,
+                                                 rs);
   if (0 >= qs)
     return qs;
   /* Now we check that the other information in @a deposit
@@ -2924,9 +2910,8 @@ postgres_have_deposit (void *cls,
             deposit2.timestamp.abs_value_us) ) ) ||
        (deposit->refund_deadline.abs_value_us !=
         deposit2.refund_deadline.abs_value_us) ||
-       (0 != memcmp (&deposit->h_wire,
-                     &deposit2.h_wire,
-                     sizeof (struct GNUNET_HashCode)) ) )
+       (0 != GNUNET_memcmp (&deposit->h_wire,
+                            &deposit2.h_wire) ) )
   {
     /* Inconsistencies detected! Does not match!  (We might want to
        expand the API with a 'get_deposit' function to return the
@@ -3294,8 +3279,8 @@ get_known_coin (void *cls,
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                         &coin_info->denom_pub.rsa_public_key),
+    GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                          &coin_info->denom_pub_hash),
     GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
                                         &coin_info->denom_sig.rsa_signature),
     GNUNET_PQ_result_spec_end
@@ -3327,10 +3312,9 @@ insert_known_coin (void *cls,
                    struct TALER_EXCHANGEDB_Session *session,
                    const struct TALER_CoinPublicInfo *coin_info)
 {
-  struct GNUNET_HashCode denom_pub_hash;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_auto_from_type (&coin_info->coin_pub),
-    GNUNET_PQ_query_param_auto_from_type (&denom_pub_hash),
+    GNUNET_PQ_query_param_auto_from_type (&coin_info->denom_pub_hash),
     GNUNET_PQ_query_param_rsa_signature (coin_info->denom_sig.rsa_signature),
     GNUNET_PQ_query_param_end
   };
@@ -3338,8 +3322,6 @@ insert_known_coin (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Creating known coin %s\n",
               TALER_B2S (&coin_info->coin_pub));
-  GNUNET_CRYPTO_rsa_public_key_hash (coin_info->denom_pub.rsa_public_key,
-                                    &denom_pub_hash);
   return GNUNET_PQ_eval_prepared_non_select (session->conn,
                                             "insert_known_coin",
                                             params);
@@ -3410,7 +3392,6 @@ postgres_ensure_coin_known (void *cls,
   }
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   {
-    GNUNET_CRYPTO_rsa_public_key_free (known_coin.denom_pub.rsa_public_key);
     GNUNET_CRYPTO_rsa_signature_free (known_coin.denom_sig.rsa_signature);
     return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; /* no change! */
   }
@@ -3650,20 +3631,20 @@ postgres_get_melt (void *cls,
     GNUNET_PQ_query_param_end
   };
   struct GNUNET_PQ_ResultSpec rs[] = {
-    GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                         
&refresh_melt->session.coin.denom_pub.rsa_public_key),
+    GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                          
&refresh_melt->session.coin.denom_pub_hash),
     TALER_PQ_result_spec_amount ("fee_refresh",
-                                &refresh_melt->melt_fee),
+                                 &refresh_melt->melt_fee),
     GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
-                                        
&refresh_melt->session.coin.denom_sig.rsa_signature),
+                                         
&refresh_melt->session.coin.denom_sig.rsa_signature),
     GNUNET_PQ_result_spec_uint32 ("noreveal_index",
-                                 &refresh_melt->session.noreveal_index),
+                                  &refresh_melt->session.noreveal_index),
     GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
-                                         &refresh_melt->session.coin.coin_pub),
+                                          
&refresh_melt->session.coin.coin_pub),
     GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
-                                         &refresh_melt->session.coin_sig),
+                                          &refresh_melt->session.coin_sig),
     TALER_PQ_result_spec_amount ("amount_with_fee",
-                                &refresh_melt->session.amount_with_fee),
+                                 &refresh_melt->session.amount_with_fee),
     GNUNET_PQ_result_spec_end
   };
   enum GNUNET_DB_QueryStatus qs;
@@ -4114,9 +4095,8 @@ add_ldl (void *cls,
       }
     }
     if ( (NULL != ldctx->last) &&
-         (0 == memcmp (&transfer_pub,
-                       &ldctx->transfer_pub,
-                       sizeof (struct TALER_TransferPublicKeyP))) )
+         (0 == GNUNET_memcmp (&transfer_pub,
+                              &ldctx->transfer_pub)) )
     {
       pos->next = ldctx->last;
     }
@@ -4474,8 +4454,8 @@ add_coin_payback (void *cls,
                                              &payback->coin_sig),
        TALER_PQ_result_spec_absolute_time ("timestamp",
                                             &payback->timestamp),
-       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                             
&payback->coin.denom_pub.rsa_public_key),
+       GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                             &payback->coin.denom_pub_hash),
        GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
                                             
&payback->coin.denom_sig.rsa_signature),
        GNUNET_PQ_result_spec_end
@@ -4964,9 +4944,8 @@ postgres_insert_wire_fee (void *cls,
     return qs;
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
   {
-    if (0 != memcmp (&sig,
-                     master_sig,
-                     sizeof (sig)))
+    if (0 != GNUNET_memcmp (&sig,
+                            master_sig))
     {
       GNUNET_break (0);
       return GNUNET_DB_STATUS_HARD_ERROR;
@@ -6361,6 +6340,7 @@ payback_serial_helper_cb (void *cls,
     struct TALER_CoinPublicInfo coin;
     struct TALER_CoinSpendSignatureP coin_sig;
     struct TALER_DenominationBlindingKeyP coin_blind;
+    struct TALER_DenominationPublicKey denom_pub;
     struct TALER_Amount amount;
     struct GNUNET_HashCode h_blind_ev;
     struct GNUNET_TIME_Absolute timestamp;
@@ -6379,8 +6359,10 @@ payback_serial_helper_cb (void *cls,
                                             &coin_blind),
       GNUNET_PQ_result_spec_auto_from_type ("h_blind_ev",
                                             &h_blind_ev),
+      GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
+                                            &coin.denom_pub_hash),
       GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
-                                            &coin.denom_pub.rsa_public_key),
+                                           &denom_pub.rsa_public_key),
       GNUNET_PQ_result_spec_rsa_signature ("denom_sig",
                                            &coin.denom_sig.rsa_signature),
       TALER_PQ_result_spec_amount ("amount",
@@ -6404,6 +6386,7 @@ payback_serial_helper_cb (void *cls,
                   &amount,
                   &reserve_pub,
                   &coin,
+                   &denom_pub,
                   &coin_sig,
                   &coin_blind);
     GNUNET_PQ_cleanup_result (rs);
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index c6e9b86a..66ccb4c7 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -271,16 +271,15 @@ create_denom_key_pair (unsigned int size,
   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
       plugin->get_denomination_info (plugin->cls,
                                      session,
-                                     &dki.denom_pub,
+                                     &dki.issue.properties.denom_hash,
                                      &issue2))
   {
     GNUNET_break(0);
     destroy_denom_key_pair (dkp);
     return NULL;
   }
-  if (0 != memcmp (&dki.issue,
-                   &issue2,
-                   sizeof (issue2)))
+  if (0 != GNUNET_memcmp (&dki.issue,
+                          &issue2))
   {
     GNUNET_break(0);
     destroy_denom_key_pair (dkp);
@@ -428,21 +427,16 @@ check_refresh_reveal_cb (void *cls,
 
     GNUNET_assert (acoin->coin_ev_size == bcoin->coin_ev_size);
     GNUNET_assert (0 ==
-                   memcmp (acoin->coin_ev,
-                           bcoin->coin_ev,
-                           acoin->coin_ev_size));
+                   GNUNET_memcmp (acoin->coin_ev,
+                                  bcoin->coin_ev));
     GNUNET_assert (0 ==
                    GNUNET_CRYPTO_rsa_public_key_cmp 
(acoin->denom_pub.rsa_public_key,
                                                      
bcoin->denom_pub.rsa_public_key));
   }
-  GNUNET_assert (0 ==
-                 memcmp (&tpub,
-                         tpr,
-                         sizeof (tpub)));
-  GNUNET_assert (0 ==
-                 memcmp (tprivs,
-                         tprivsr,
-                         sizeof (struct TALER_TransferPrivateKeyP) * 
(TALER_CNC_KAPPA - 1)));
+  GNUNET_assert(0 == GNUNET_memcmp(&tpub, tpr));
+  GNUNET_assert(0 == memcmp(tprivs, tprivsr,
+                            sizeof(struct TALER_TransferPrivateKeyP) *
+                                (TALER_CNC_KAPPA - 1)));
 }
 
 
@@ -580,7 +574,8 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
         GNUNET_CRYPTO_rsa_sign_fdh (dkp->priv.rsa_private_key,
                                     &hc);
     GNUNET_assert (NULL != refresh_session.coin.denom_sig.rsa_signature);
-    refresh_session.coin.denom_pub = dkp->pub;
+    GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key,
+                                       &refresh_session.coin.denom_pub_hash);
     refresh_session.amount_with_fee = amount_with_fee;
   }
 
@@ -611,14 +606,10 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
   FAILIF (0 !=
           TALER_amount_cmp (&fee_refresh,
                             &ret_refresh_session.melt_fee));
-  FAILIF (0 !=
-          memcmp (&refresh_session.rc,
-                  &ret_refresh_session.session.rc,
-                  sizeof (struct TALER_RefreshCommitmentP)));
-  FAILIF (0 !=
-          memcmp (&refresh_session.coin_sig,
-                  &ret_refresh_session.session.coin_sig,
-                  sizeof (struct TALER_CoinSpendSignatureP)));
+  FAILIF(0 !=
+         GNUNET_memcmp(&refresh_session.rc, &ret_refresh_session.session.rc));
+  FAILIF(0 != GNUNET_memcmp(&refresh_session.coin_sig,
+                            &ret_refresh_session.session.coin_sig));
   FAILIF (0 !=
           GNUNET_CRYPTO_rsa_signature_cmp 
(refresh_session.coin.denom_sig.rsa_signature,
                                            
ret_refresh_session.session.coin.denom_sig.rsa_signature));
@@ -626,10 +617,9 @@ test_melting (struct TALER_EXCHANGEDB_Session *session)
                        &ret_refresh_session.session.coin.coin_pub,
                        sizeof (refresh_session.coin.coin_pub)));
   FAILIF (0 !=
-          GNUNET_CRYPTO_rsa_public_key_cmp 
(refresh_session.coin.denom_pub.rsa_public_key,
-                                            
ret_refresh_session.session.coin.denom_pub.rsa_public_key));
+          GNUNET_memcmp (&refresh_session.coin.denom_pub_hash,
+                         &ret_refresh_session.session.coin.denom_pub_hash));
   GNUNET_CRYPTO_rsa_signature_free 
(ret_refresh_session.session.coin.denom_sig.rsa_signature);
-  GNUNET_CRYPTO_rsa_public_key_free 
(ret_refresh_session.session.coin.denom_pub.rsa_public_key);
 
   /* test 'select_refreshs_above_serial_id' */
   auditor_row_cnt = 0;
@@ -817,22 +807,18 @@ cb_wt_check (void *cls,
              const struct TALER_Amount *coin_fee)
 {
   GNUNET_assert (cls == &cb_wt_never);
-  GNUNET_assert (0 == memcmp (merchant_pub,
-                              &merchant_pub_wt,
-                              sizeof (struct TALER_MerchantPublicKeyP)));
+  GNUNET_assert (0 == GNUNET_memcmp (merchant_pub,
+                                     &merchant_pub_wt));
   GNUNET_assert (0 == strcmp (json_string_value (json_object_get (wire,
                                                                   "url")),
                               "payto://sepa/DE67830654080004822650"));
-  GNUNET_assert (0 == memcmp (h_wire,
-                              &h_wire_wt,
-                              sizeof (struct GNUNET_HashCode)));
+  GNUNET_assert (0 == GNUNET_memcmp (h_wire,
+                                     &h_wire_wt));
   GNUNET_assert (exec_time.abs_value_us == wire_out_date.abs_value_us);
-  GNUNET_assert (0 == memcmp (h_contract_terms,
-                              &h_contract_terms_wt,
-                              sizeof (struct GNUNET_HashCode)));
-  GNUNET_assert (0 == memcmp (coin_pub,
-                              &coin_pub_wt,
-                              sizeof (struct TALER_CoinSpendPublicKeyP)));
+  GNUNET_assert (0 == GNUNET_memcmp (h_contract_terms,
+                                     &h_contract_terms_wt));
+  GNUNET_assert (0 == GNUNET_memcmp (coin_pub,
+                                     &coin_pub_wt));
   GNUNET_assert (0 == TALER_amount_cmp (coin_value,
                                         &coin_value_wt));
   GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
@@ -851,9 +837,8 @@ cb_wtid_check (void *cls,
                struct GNUNET_TIME_Absolute execution_time)
 {
   GNUNET_assert (cls == &cb_wtid_never);
-  GNUNET_assert (0 == memcmp (wtid,
-                              &wire_out_wtid,
-                              sizeof (struct 
TALER_WireTransferIdentifierRawP)));
+  GNUNET_assert (0 == GNUNET_memcmp (wtid,
+                                     &wire_out_wtid));
   GNUNET_assert (execution_time.abs_value_us ==
                  wire_out_date.abs_value_us);
   GNUNET_assert (0 == TALER_amount_cmp (coin_contribution,
@@ -906,23 +891,20 @@ deposit_cb (void *cls,
     GNUNET_assert (GNUNET_OK ==
                    TALER_JSON_merchant_wire_signature_hash (wire,
                                                             &h_wire));
-  if ( (0 != memcmp (merchant_pub,
-                     &deposit->merchant_pub,
-                     sizeof (struct TALER_MerchantPublicKeyP))) ||
+  if ( (0 != GNUNET_memcmp (merchant_pub,
+                            &deposit->merchant_pub)) ||
        (0 != TALER_amount_cmp (amount_with_fee,
                                &deposit->amount_with_fee)) ||
        (0 != TALER_amount_cmp (deposit_fee,
                                &deposit->deposit_fee)) ||
-       (0 != memcmp (h_contract_terms,
-                     &deposit->h_contract_terms,
-                     sizeof (struct GNUNET_HashCode))) ||
+       (0 != GNUNET_memcmp (h_contract_terms,
+                            &deposit->h_contract_terms)) ||
        (0 != memcmp (coin_pub,
                      &deposit->coin.coin_pub,
                      sizeof (struct TALER_CoinSpendPublicKeyP))) ||
        ( (NULL != wire) &&
-         (0 != memcmp (&h_wire,
-                       &deposit->h_wire,
-                       sizeof (struct GNUNET_HashCode))) ) )
+         (0 != GNUNET_memcmp (&h_wire,
+                              &deposit->h_wire)) ) )
   {
     GNUNET_break (0);
     return GNUNET_DB_STATUS_HARD_ERROR;
@@ -1075,6 +1057,7 @@ test_gc (struct TALER_EXCHANGEDB_Session *session)
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_TIME_Absolute past;
   struct TALER_EXCHANGEDB_DenominationKeyInformationP issue2;
+  struct GNUNET_HashCode denom_hash;
 
   now = GNUNET_TIME_absolute_get ();
   GNUNET_TIME_round_abs (&now);
@@ -1097,10 +1080,13 @@ test_gc (struct TALER_EXCHANGEDB_Session *session)
     destroy_denom_key_pair (dkp);
     return GNUNET_SYSERR;
   }
+    GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key,
+                                       &denom_hash);
+
   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
       plugin->get_denomination_info (plugin->cls,
                                      session,
-                                     &dkp->pub,
+                                     &denom_hash,
                                      &issue2))
   {
     GNUNET_break(0);
@@ -1207,9 +1193,8 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session)
                                &wire_fee)) ||
        (0 != TALER_amount_cmp (&fee2,
                                &closing_fee)) ||
-       (0 != memcmp (&ms,
-                     &master_sig,
-                     sizeof (ms))) )
+       (0 != GNUNET_memcmp (&ms,
+                            &master_sig)) )
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -1245,9 +1230,8 @@ audit_wire_cb (void *cls,
                  TALER_amount_cmp (amount,
                                    &wire_out_amount));
   GNUNET_assert (0 ==
-                 memcmp (wtid,
-                         &wire_out_wtid,
-                         sizeof (*wtid)));
+                 GNUNET_memcmp (wtid,
+                                &wire_out_wtid));
   GNUNET_assert (date.abs_value_us == wire_out_date.abs_value_us);
   return GNUNET_OK;
 }
@@ -1396,14 +1380,14 @@ payback_cb (void *cls,
             const struct TALER_Amount *amount,
             const struct TALER_ReservePublicKeyP *reserve_pub,
             const struct TALER_CoinPublicInfo *coin,
+            const struct TALER_DenominationPublicKey *denom_pub,
             const struct TALER_CoinSpendSignatureP *coin_sig,
             const struct TALER_DenominationBlindingKeyP *coin_blind)
 {
   const struct TALER_DenominationBlindingKeyP *cb = cls;
 
-  FAILIF (0 != memcmp (cb,
-                       coin_blind,
-                       sizeof (*cb)));
+  FAILIF (0 != GNUNET_memcmp (cb,
+                              coin_blind));
   return GNUNET_OK;
  drop:
   return GNUNET_SYSERR;
@@ -1460,16 +1444,14 @@ wire_missing_cb (void *cls,
     GNUNET_break (0);
     result = 66;
   }
-  if (0 != memcmp (coin_pub,
-                   &deposit->coin.coin_pub,
-                   sizeof (struct TALER_CoinSpendPublicKeyP)))
+  if (0 != GNUNET_memcmp (coin_pub,
+                          &deposit->coin.coin_pub))
   {
     GNUNET_break (0);
     result = 66;
   }
-  if (0 != memcmp (&h_wire,
-                   &deposit->h_wire,
-                   sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (&h_wire,
+                          &deposit->h_wire))
   {
     GNUNET_break (0);
     result = 66;
@@ -1501,23 +1483,20 @@ check_refund_cb (void *cls,
 {
   const struct TALER_EXCHANGEDB_Refund *refund = cls;
 
-  if (0 != memcmp (merchant_pub,
-                  &refund->merchant_pub,
-                  sizeof (struct TALER_MerchantPublicKeyP)))
+  if (0 != GNUNET_memcmp (merchant_pub,
+                          &refund->merchant_pub))
   {
     GNUNET_break (0);
     result = 66;
   }
-  if (0 != memcmp (merchant_sig,
-                  &refund->merchant_sig,
-                  sizeof (struct TALER_MerchantSignatureP)))
+  if (0 != GNUNET_memcmp (merchant_sig,
+                          &refund->merchant_sig))
   {
     GNUNET_break (0);
     result = 66;
   }
-  if (0 != memcmp (h_contract,
-                  &refund->h_contract_terms,
-                  sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (h_contract,
+                          &refund->h_contract_terms))
   {
     GNUNET_break (0);
     result = 66;
@@ -1726,7 +1705,7 @@ run (void *cls)
                                      &dkp_pub_hash);
   RND_BLK(&cbc.h_coin_envelope);
   RND_BLK(&cbc.reserve_sig);
-  cbc.denom_pub = dkp->pub;
+  cbc.denom_pub_hash = dkp_pub_hash;
   cbc.sig.rsa_signature
     = GNUNET_CRYPTO_rsa_sign_fdh (dkp->priv.rsa_private_key,
                                   &cbc.h_coin_envelope);
@@ -1750,22 +1729,16 @@ run (void *cls)
                                           session,
                                           &cbc.h_coin_envelope,
                                           &reserve_pub2));
-  FAILIF (0 != memcmp (&reserve_pub,
-                       &reserve_pub2,
-                       sizeof (reserve_pub)));
+  FAILIF (0 != GNUNET_memcmp (&reserve_pub,
+                              &reserve_pub2));
 
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
           plugin->get_withdraw_info (plugin->cls,
                                      session,
                                      &cbc.h_coin_envelope,
                                      &cbc2));
-  FAILIF (NULL == cbc2.denom_pub.rsa_public_key);
-  FAILIF (0 != memcmp (&cbc2.reserve_sig,
-                       &cbc.reserve_sig,
-                       sizeof (cbc2.reserve_sig)));
-  FAILIF (0 != memcmp (&cbc2.reserve_pub,
-                       &cbc.reserve_pub,
-                       sizeof (cbc2.reserve_pub)));
+  FAILIF(0 != GNUNET_memcmp(&cbc2.reserve_sig, &cbc.reserve_sig));
+  FAILIF(0 != GNUNET_memcmp(&cbc2.reserve_pub, &cbc.reserve_pub));
   result = 6;
   FAILIF (GNUNET_OK !=
           GNUNET_CRYPTO_rsa_verify (&cbc.h_coin_envelope,
@@ -1776,7 +1749,8 @@ run (void *cls)
   RND_BLK (&coin_sig);
   RND_BLK (&coin_blind);
   RND_BLK (&deposit.coin.coin_pub);
-  deposit.coin.denom_pub = dkp->pub;
+  GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key,
+                                     &deposit.coin.denom_pub_hash);
   deposit.coin.denom_sig = cbc.sig;
   deadline = GNUNET_TIME_absolute_get ();
   (void) GNUNET_TIME_round_abs (&deadline);
@@ -1916,7 +1890,8 @@ run (void *cls)
           0,
           sizeof (deposit));
   RND_BLK (&deposit.coin.coin_pub);
-  deposit.coin.denom_pub = dkp->pub;
+  GNUNET_CRYPTO_rsa_public_key_hash (dkp->pub.rsa_public_key,
+                                     &deposit.coin.denom_pub_hash);
   deposit.coin.denom_sig = cbc.sig;
   RND_BLK (&deposit.csig);
   RND_BLK (&deposit.merchant_pub);
@@ -2105,9 +2080,8 @@ run (void *cls)
                                                  &dkp_pub_hash,
                                                  &msig,
                                                 &rev_rowid));
-    FAILIF (0 != memcmp (&msig,
-                         &master_sig,
-                         sizeof (msig)));
+    FAILIF (0 != GNUNET_memcmp (&msig,
+                                &master_sig));
   }
 
 
@@ -2197,15 +2171,12 @@ run (void *cls)
         /* Note: we're not comparing the denomination keys, as there is
            still the question of whether we should even bother exporting
            them here. */
-        FAILIF (0 != memcmp (&have->merchant_pub,
-                             &refund.merchant_pub,
-                             sizeof (struct TALER_MerchantPublicKeyP)));
-        FAILIF (0 != memcmp (&have->merchant_sig,
-                             &refund.merchant_sig,
-                             sizeof (struct TALER_MerchantSignatureP)));
-        FAILIF (0 != memcmp (&have->h_contract_terms,
-                             &refund.h_contract_terms,
-                             sizeof (struct GNUNET_HashCode)));
+        FAILIF (0 != GNUNET_memcmp (&have->merchant_pub,
+                                    &refund.merchant_pub));
+        FAILIF (0 != GNUNET_memcmp (&have->merchant_sig,
+                                    &refund.merchant_sig));
+        FAILIF (0 != GNUNET_memcmp (&have->h_contract_terms,
+                                    &refund.h_contract_terms));
         FAILIF (have->rtransaction_id != refund.rtransaction_id);
         FAILIF (0 != TALER_amount_cmp (&have->refund_amount,
                                        &refund.refund_amount));
@@ -2218,15 +2189,12 @@ run (void *cls)
       {
         struct TALER_EXCHANGEDB_Payback *payback = tlp->details.payback;
 
-        FAILIF (0 != memcmp (&payback->coin_sig,
-                             &coin_sig,
-                             sizeof (coin_sig)));
-        FAILIF (0 != memcmp (&payback->coin_blind,
-                             &coin_blind,
-                             sizeof (coin_blind)));
-        FAILIF (0 != memcmp (&payback->reserve_pub,
-                             &reserve_pub,
-                             sizeof (reserve_pub)));
+        FAILIF (0 != GNUNET_memcmp (&payback->coin_sig,
+                                    &coin_sig));
+        FAILIF (0 != GNUNET_memcmp (&payback->coin_blind,
+                                    &coin_blind));
+        FAILIF (0 != GNUNET_memcmp (&payback->reserve_pub,
+                                    &reserve_pub));
         FAILIF (0 != memcmp (&payback->coin.coin_pub,
                              &deposit.coin.coin_pub,
                              sizeof (deposit.coin.coin_pub)));
@@ -2297,8 +2265,6 @@ run (void *cls)
     destroy_denom_key_pair (dkp);
   if (NULL != cbc.sig.rsa_signature)
     GNUNET_CRYPTO_rsa_signature_free (cbc.sig.rsa_signature);
-  if (NULL != cbc2.denom_pub.rsa_public_key)
-    GNUNET_CRYPTO_rsa_public_key_free (cbc2.denom_pub.rsa_public_key);
   if (NULL != cbc2.sig.rsa_signature)
     GNUNET_CRYPTO_rsa_signature_free (cbc2.sig.rsa_signature);
   dkp = NULL;
diff --git a/src/exchangedb/test_exchangedb_auditors.c 
b/src/exchangedb/test_exchangedb_auditors.c
index bc5d378f..9424919c 100644
--- a/src/exchangedb/test_exchangedb_auditors.c
+++ b/src/exchangedb/test_exchangedb_auditors.c
@@ -78,30 +78,26 @@ auditor_cb (void *cls,
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  if (0 != memcmp (&want_apub,
-                   apub,
-                   sizeof (struct TALER_AuditorPublicKeyP)))
+  if (0 != GNUNET_memcmp (&want_apub,
+                          apub))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  if (0 != memcmp (&want_mpub,
-                   mpub,
-                   sizeof (struct TALER_MasterPublicKeyP)))
+  if (0 != GNUNET_memcmp (&want_mpub,
+                          mpub))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  if (0 != memcmp (&want_asigs,
-                   asigs,
-                   sizeof (struct TALER_AuditorSignatureP)))
+  if (0 != GNUNET_memcmp (&want_asigs,
+                          asigs))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  if (0 != memcmp (&want_dki,
-                   dki,
-                   sizeof (struct TALER_DenominationKeyValidityPS)))
+  if (0 != GNUNET_memcmp (&want_dki,
+                          dki))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
diff --git a/src/exchangedb/test_exchangedb_denomkeys.c 
b/src/exchangedb/test_exchangedb_denomkeys.c
index b558b3b3..a8e7af04 100644
--- a/src/exchangedb/test_exchangedb_denomkeys.c
+++ b/src/exchangedb/test_exchangedb_denomkeys.c
@@ -49,9 +49,8 @@ dki_iter (void *cls,
 {
   const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls;
 
-  if (0 != memcmp (&exp->issue,
-                   &dki->issue,
-                   sizeof (struct 
TALER_EXCHANGEDB_DenominationKeyInformationP)))
+  if (0 != GNUNET_memcmp (&exp->issue,
+                          &dki->issue))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -96,9 +95,8 @@ dki_iter_revoked (void *cls,
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  if (0 != memcmp (denom_hash,
-                   &exp->issue.properties.denom_hash,
-                   sizeof (struct GNUNET_HashCode)))
+  if (0 != GNUNET_memcmp (denom_hash,
+                          &exp->issue.properties.denom_hash))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
diff --git a/src/exchangedb/test_exchangedb_signkeys.c 
b/src/exchangedb/test_exchangedb_signkeys.c
index 2ab38c66..9ff42308 100644
--- a/src/exchangedb/test_exchangedb_signkeys.c
+++ b/src/exchangedb/test_exchangedb_signkeys.c
@@ -47,9 +47,8 @@ ski_iter (void *cls,
 {
   const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *exp = cls;
 
-  if (0 != memcmp (ski,
-                   exp,
-                   sizeof (struct 
TALER_EXCHANGEDB_PrivateSigningKeyInformationP)))
+  if (0 != GNUNET_memcmp (ski,
+                          exp))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h
index 2f4a0602..2cebbe6e 100644
--- a/src/include/taler_bank_service.h
+++ b/src/include/taler_bank_service.h
@@ -101,6 +101,7 @@ struct TALER_BANK_AdminAddIncomingHandle;
  *                    0 if the bank's reply is bogus (fails to follow the 
protocol)
  * @param ec detailed error code
  * @param serial_id unique ID of the wire transfer in the bank's records; 
UINT64_MAX on error
+ * @param timestamp time when the transaction was made.
  * @param json detailed response from the HTTPD, or NULL if reply was not in 
JSON
  */
 typedef void
@@ -108,6 +109,7 @@ typedef void
                                               unsigned int http_status,
                                               enum TALER_ErrorCode ec,
                                               uint64_t serial_id,
+                                              struct GNUNET_TIME_Absolute 
timestamp,
                                               const json_t *json);
 
 
@@ -282,6 +284,41 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
 
 
 /**
+ * Request the wire transfer history of a bank account,
+ * using time stamps to narrow the results.
+ *
+ * @param ctx curl context for the event loop
+ * @param bank_base_url URL of the bank (used to execute this
+ *        request)
+ * @param auth authentication data to use
+ * @param account_number which account number should we query
+ * @param direction what kinds of wire transfers should be
+ *        returned
+ * @param ascending if GNUNET_YES, history elements will
+ *        be returned in chronological order.
+ * @param start_date threshold for oldest result.
+ * @param end_date threshold for youngest result.
+ * @param hres_cb the callback to call with the transaction
+ *        history
+ * @param hres_cb_cls closure for the above callback
+ * @return NULL if the inputs are invalid (i.e. zero value for
+ *         @e num_results). In this case, the callback is not
+ *         called.
+ */
+struct TALER_BANK_HistoryHandle *
+TALER_BANK_history_range (struct GNUNET_CURL_Context *ctx,
+                          const char *bank_base_url,
+                          const struct TALER_BANK_AuthenticationData *auth,
+                          uint64_t account_number,
+                          enum TALER_BANK_Direction direction,
+                          unsigned int ascending,
+                          struct GNUNET_TIME_Absolute start_date,
+                          struct GNUNET_TIME_Absolute end_date,
+                          TALER_BANK_HistoryResultCallback hres_cb,
+                          void *hres_cb_cls);
+
+
+/**
  * Cancel an history request.  This function cannot be used on a request
  * handle if the last response (anything with a status code other than
  * 200) is already served for it.
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index f1251617..18c214e1 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -354,10 +354,10 @@ struct TALER_CoinPublicInfo
   struct TALER_CoinSpendPublicKeyP coin_pub;
 
   /**
-   * Public key representing the denomination of the coin
-   * that is being deposited.
+   * Hash of the public key representing the denomination of the coin that is
+   * being deposited.
    */
-  struct TALER_DenominationPublicKey denom_pub;
+  struct GNUNET_HashCode denom_pub_hash;
 
   /**
    * (Unblinded) signature over @e coin_pub with @e denom_pub,
@@ -401,12 +401,14 @@ struct TALER_TrackTransferDetails
  * is not expired, and the signature is correct.
  *
  * @param coin_public_info the coin public info to check for validity
+ * @param denom_pub denomination key, must match @a coin_public_info's 
`denom_pub_hash`
  * @return #GNUNET_YES if the coin is valid,
  *         #GNUNET_NO if it is invalid
  *         #GNUNET_SYSERR if an internal error occured
  */
 int
-TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info);
+TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info,
+                       const struct TALER_DenominationPublicKey *denom_pub);
 
 
 GNUNET_NETWORK_STRUCT_BEGIN
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 88fcf74a..880e6038 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -422,6 +422,26 @@ TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle 
*exchange);
 const struct TALER_EXCHANGE_Keys *
 TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange);
 
+
+/**
+ * Set the fake now to be used when requesting "/keys".
+ *
+ * @param exchange exchange handle.
+ * @param now fake now to use.  Note: this value will be
+ *        used _until_ its use will be unset via @a TALER_EXCHANGE_unset_now()
+ */
+void
+TALER_EXCHANGE_set_now (struct TALER_EXCHANGE_Handle *exchange,
+                        struct GNUNET_TIME_Absolute now);
+
+/**
+ * Unset the fake now to be used when requesting "/keys".
+ *
+ * @param exchange exchange handle.
+ */
+void
+TALER_EXCHANGE_unset_now (struct TALER_EXCHANGE_Handle *exchange);
+
 /**
  * Let the user set the last valid denomination time manually.
  *
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index 2d9f1420..0a46c726 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -147,9 +147,9 @@ struct TALER_EXCHANGEDB_CollectableBlindcoin
   struct TALER_DenominationSignature sig;
 
   /**
-   * Denomination key (which coin was generated).
+   * Hash of the denomination key (which coin was generated).
    */
-  struct TALER_DenominationPublicKey denom_pub;
+  struct GNUNET_HashCode denom_pub_hash;
 
   /**
    * Value of the coin being exchangeed (matching the denomination key)
@@ -1045,6 +1045,7 @@ typedef int
                                     const struct TALER_Amount *amount,
                                     const struct TALER_ReservePublicKeyP 
*reserve_pub,
                                     const struct TALER_CoinPublicInfo *coin,
+                                    const struct TALER_DenominationPublicKey 
*denom_pub,
                                     const struct TALER_CoinSpendSignatureP 
*coin_sig,
                                     const struct 
TALER_DenominationBlindingKeyP *coin_blind);
 
@@ -1274,14 +1275,14 @@ struct TALER_EXCHANGEDB_Plugin
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param session connection to use
-   * @param denom_pub the public key used for signing coins of this 
denomination
+   * @param denom_pub_hash hash of the public key used for signing coins of 
this denomination
    * @param[out] issue set to issue information with value, fees and other 
info about the coin
    * @return transaction status code
    */
   enum GNUNET_DB_QueryStatus
   (*get_denomination_info) (void *cls,
                             struct TALER_EXCHANGEDB_Session *session,
-                            const struct TALER_DenominationPublicKey 
*denom_pub,
+                            const struct GNUNET_HashCode *denom_pub_hash,
                             struct 
TALER_EXCHANGEDB_DenominationKeyInformationP *issue);
 
 
diff --git a/src/include/taler_testing_bank_lib.h 
b/src/include/taler_testing_bank_lib.h
index a3cc741e..5beaf97f 100644
--- a/src/include/taler_testing_bank_lib.h
+++ b/src/include/taler_testing_bank_lib.h
@@ -109,6 +109,63 @@ TALER_TESTING_cmd_bank_history
    const char *start_row_reference,
    long long num_results);
 
+
+/**
+ * Make a "history-range" CMD, picking dates from the arguments.
+ *
+ * @param label command label.
+ * @param bank_url base URL of the bank offering the "history"
+ *        operation.
+ * @param account_no bank account number to ask the history for.
+ * @param direction which direction this operation is interested.
+ * @param ascending if GNUNET_YES, the bank will return the rows
+ *        in ascending (= chronological) order.
+ * @param start_date value for the 'start' argument
+ *        of "/history-range".
+ * @param end_date value for the 'end' argument
+ *        of "/history-range".
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_history_range_with_dates
+  (const char *label,
+   const char *bank_url,
+   uint64_t account_no,
+   enum TALER_BANK_Direction direction,
+   unsigned int ascending,
+   struct GNUNET_TIME_Absolute start_date,
+   struct GNUNET_TIME_Absolute end_date);
+
+
+/**
+ * Make a "history-range" CMD, picking dates from traits.
+ *
+ * @param label command label.
+ * @param bank_url base URL of the bank offering the "history"
+ *        operation.
+ * @param account_no bank account number to ask the history for.
+ * @param direction which direction this operation is interested.
+ * @param ascending if GNUNET_YES, the bank will return the rows
+ *        in ascending (= chronological) order.
+ * @param start_row_reference reference to a command that can
+ *        offer a absolute time to use as the 'start' argument
+ *        for "/history-range".
+ * @param end_row_reference reference to a command that can
+ *        offer a absolute time to use as the 'end' argument
+ *        for "/history-range".
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_history_range
+  (const char *label,
+   const char *bank_url,
+   uint64_t account_no,
+   enum TALER_BANK_Direction direction,
+   unsigned int ascending,
+   const char *start_row_reference,
+   const char *end_row_reference);
+
+
 /**
  * Create a "reject" CMD.
  *
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index 711a1323..99be529b 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -654,8 +654,9 @@ struct TALER_TESTING_SetupContext
  * @return #GNUNET_OK if no errors occurred.
  */
 int
-TALER_TESTING_setup_with_exchange_cfg (void *cls,
-                                       const struct 
GNUNET_CONFIGURATION_Handle *cfg);
+TALER_TESTING_setup_with_exchange_cfg
+  (void *cls,
+   const struct GNUNET_CONFIGURATION_Handle *cfg);
 
 
 /**
@@ -681,22 +682,23 @@ TALER_TESTING_setup_with_exchange (TALER_TESTING_Main 
main_cb,
 
 /**
  * Initialize scheduler loop and curl context for the test case
- * including starting and stopping the auditor and exchange using the
- * given configuration file.
+ * including starting and stopping the auditor and exchange using
+ * the given configuration file.
  *
  * @param cls must be a `struct TALER_TESTING_SetupContext *`
  * @param cfg configuration to use.
  * @return #GNUNET_OK if no errors occurred.
  */
 int
-TALER_TESTING_setup_with_auditor_and_exchange_cfg (void *cls,
-                                                   const struct 
GNUNET_CONFIGURATION_Handle *cfg);
+TALER_TESTING_setup_with_auditor_and_exchange_cfg
+  (void *cls,
+   const struct GNUNET_CONFIGURATION_Handle *cfg);
 
 
 /**
  * Initialize scheduler loop and curl context for the test case
- * including starting and stopping the auditor and exchange using the
- * given configuration file.
+ * including starting and stopping the auditor and exchange using
+ * the given configuration file.
  *
  * @param main_cb main method.
  * @param main_cb_cls main method closure.
@@ -709,12 +711,10 @@ TALER_TESTING_setup_with_auditor_and_exchange_cfg (void 
*cls,
  * @return #GNUNET_OK if no errors occurred.
  */
 int
-TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,
-                                               void *main_cb_cls,
-                                               const char *config_file);
-
-
-
+TALER_TESTING_setup_with_auditor_and_exchange
+  (TALER_TESTING_Main main_cb,
+   void *main_cb_cls,
+   const char *config_file);
 
 /* ************** Specific interpreter commands ************ */
 
@@ -872,14 +872,15 @@ TALER_TESTING_cmd_fakebank_transfer_with_instance
 
 /**
  * Modify a fakebank transfer command to enable retries when the
- * reserve is not yet full or we get other transient errors from the
- * fakebank.
+ * reserve is not yet full or we get other transient errors from
+ * the fakebank.
  *
  * @param cmd a fakebank transfer command
  * @return the command with retries enabled
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_fakebank_transfer_retry (struct TALER_TESTING_Command cmd);
+TALER_TESTING_cmd_fakebank_transfer_retry
+  (struct TALER_TESTING_Command cmd);
 
 
 /**
@@ -920,6 +921,46 @@ TALER_TESTING_cmd_exec_keyup (const char *label,
                               const char *config_filename);
 
 /**
+ * Make the "keyup" CMD, with "--timestamp" option.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ * @param now Unix timestamp representing the fake "now".
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_keyup_with_now
+  (const char *label,
+   const char *config_filename,
+   struct GNUNET_TIME_Absolute now);
+
+
+/**
+ * Make a "check keys" command.  This type of command
+ * checks whether the number of denomination keys from
+ * @a exchange matches @a num_denom_keys.
+ *
+ * @param label command label
+ * @param generation when this command is run, exactly @a
+ *        generation /keys downloads took place.  If the number
+ *        of downloads is less than @a generation, the logic will
+ *        first make sure that @a generation downloads are done,
+ *        and _then_ execute the rest of the command.
+ * @param num_denom_keys expected number of denomination keys.
+ * @param exchange connection handle to the exchange to test.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_keys_with_now
+  (const char *label,
+   unsigned int generation,
+   unsigned int num_denom_keys,
+   struct GNUNET_TIME_Absolute now);
+
+
+/**
  * Make a "auditor sign" CMD.
  *
  * @param label command label
@@ -980,7 +1021,8 @@ TALER_TESTING_cmd_withdraw_denomination
  * @return the command with retries enabled
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd);
+TALER_TESTING_cmd_withdraw_with_retry
+  (struct TALER_TESTING_Command cmd);
 
 
 /**
@@ -1058,7 +1100,8 @@ TALER_TESTING_cmd_deposit
  * @return the command with retries enabled
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd);
+TALER_TESTING_cmd_deposit_with_retry
+  (struct TALER_TESTING_Command cmd);
 
 
 /**
@@ -1108,7 +1151,8 @@ TALER_TESTING_cmd_refresh_melt_double
  * @return modified command.
  */
 struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_melt_with_retry (struct TALER_TESTING_Command cmd);
+TALER_TESTING_cmd_refresh_melt_with_retry
+  (struct TALER_TESTING_Command cmd);
 
 
 /**
@@ -1398,6 +1442,19 @@ TALER_TESTING_cmd_sleep (const char *label,
 
 
 /**
+ * This CMD simply tries to connect via HTTP to the
+ * service addressed by @a url.  It attemps 10 times
+ * before giving up and make the test fail.
+ *
+ * @param label label for the command.
+ * @param url complete URL to connect to.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wait_service (const char *label,
+                                const char *url);
+
+
+/**
  * Make a "check keys" command.  This type of command
  * checks whether the number of denomination keys from
  * @a exchange matches @a num_denom_keys.
@@ -2367,4 +2424,32 @@ TALER_TESTING_get_trait_cmd
    struct TALER_TESTING_Command **_cmd);
 
 
+/**
+ * Obtain a absolute time from @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index which time stamp to pick if
+ *        @a cmd has multiple on offer.
+ * @param time[out] set to the wanted WTID.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_absolute_time
+  (const struct TALER_TESTING_Command *cmd,
+   unsigned int index,
+   const struct GNUNET_TIME_Absolute **time);
+
+
+/**
+ * Offer a absolute time.
+ *
+ * @param index associate the object with this index
+ * @param time which object should be returned
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_absolute_time
+  (unsigned int index,
+   const struct GNUNET_TIME_Absolute *time);
+
 #endif
diff --git a/src/include/taler_wire_plugin.h b/src/include/taler_wire_plugin.h
index 57122a43..ff89593e 100644
--- a/src/include/taler_wire_plugin.h
+++ b/src/include/taler_wire_plugin.h
@@ -310,6 +310,30 @@ struct TALER_WIRE_Plugin
                   TALER_WIRE_HistoryResultCallback hres_cb,
                   void *hres_cb_cls);
 
+  /**
+   * Query transfer history of an account.  The query is based on
+   * the dates where the wire transfers got settled at the bank.
+   *
+   * @param cls the @e cls of this struct with the plugin-specific state
+   * @param account_section specifies the configuration section which
+   *        identifies the account for which we should get the history
+   * @param direction what kinds of wire transfers should be returned
+   * @param start_date each history entry in the result will be time
+   *        stamped after, or at this date.
+   * @param end_date each history entry in the result will be time
+   *        stamped before, or at this date.
+   * @param hres_cb the callback to call with the transaction history
+   * @param hres_cb_cls closure for the above callback
+   * @param return the operation handle, or NULL on errors.
+   */
+  struct TALER_WIRE_HistoryHandle *
+  (*get_history_range) (void *cls,
+                        const char *account_section,
+                        enum TALER_BANK_Direction direction,
+                        struct GNUNET_TIME_Absolute start_date,
+                        struct GNUNET_TIME_Absolute end_date,
+                        TALER_WIRE_HistoryResultCallback hres_cb,
+                        void *hres_cb_cls);
 
   /**
    * Cancel going over the account's history.
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index adf075fa..0aa78d7b 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -27,7 +27,8 @@ libtalerexchange_la_SOURCES = \
   exchange_api_reserve.c \
   exchange_api_track_transaction.c \
   exchange_api_track_transfer.c \
-  exchange_api_wire.c
+  exchange_api_wire.c \
+  teah_common.c teah_common.h
 libtalerexchange_la_LIBADD = \
   libtalerauditor.la \
   $(top_builddir)/src/json/libtalerjson.la \
@@ -46,7 +47,8 @@ libtalerauditor_la_SOURCES = \
   auditor_api_curl_defaults.c auditor_api_curl_defaults.h \
   auditor_api_handle.c auditor_api_handle.h \
   auditor_api_deposit_confirmation.c \
-  auditor_api_exchanges.c
+  auditor_api_exchanges.c \
+  teah_common.c teah_common.h
 libtalerauditor_la_LIBADD = \
   $(top_builddir)/src/json/libtalerjson.la \
   $(top_builddir)/src/util/libtalerutil.la \
@@ -107,7 +109,8 @@ libtalertesting_la_SOURCES = \
   testing_api_trait_key_peer.c \
   testing_api_trait_wtid.c \
   testing_api_trait_amount.c \
-  testing_api_trait_cmd.c
+  testing_api_trait_cmd.c \
+  testing_api_trait_time.c
 libtalertesting_la_LIBADD = \
   libtalerexchange.la \
   $(top_builddir)/src/wire/libtalerwire.la \
diff --git a/src/lib/auditor_api_curl_defaults.c 
b/src/lib/auditor_api_curl_defaults.c
index d5b92400..507ae0e5 100644
--- a/src/lib/auditor_api_curl_defaults.c
+++ b/src/lib/auditor_api_curl_defaults.c
@@ -44,12 +44,10 @@ TAL_curl_easy_get (const char *url)
                  curl_easy_setopt (eh,
                                    CURLOPT_ENCODING,
                                    "deflate"));
-#ifdef CURLOPT_TCP_FASTOPEN
   GNUNET_assert (CURLE_OK ==
                  curl_easy_setopt (eh,
                                    CURLOPT_TCP_FASTOPEN,
                                    1L));
-#endif
   {
     /* Unfortunately libcurl needs chunk to be alive until after
     curl_easy_perform.  To avoid manual cleanup, we keep
diff --git a/src/lib/auditor_api_deposit_confirmation.c 
b/src/lib/auditor_api_deposit_confirmation.c
index c34890e6..bb637797 100644
--- a/src/lib/auditor_api_deposit_confirmation.c
+++ b/src/lib/auditor_api_deposit_confirmation.c
@@ -49,9 +49,10 @@ struct TALER_AUDITOR_DepositConfirmationHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Handle for the request.
@@ -338,26 +339,26 @@ TALER_AUDITOR_deposit_confirmation (struct 
TALER_AUDITOR_Handle *auditor,
   dh->url = MAH_path_to_url (auditor, "/deposit-confirmation");
 
   eh = TAL_curl_easy_get (dh->url);
-  GNUNET_assert (NULL != (dh->json_enc =
-                          json_dumps (deposit_confirmation_obj,
-                                      JSON_COMPACT)));
-  json_decref (deposit_confirmation_obj);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "URL for deposit-confirmation: `%s'\n",
-              dh->url);
-
   GNUNET_assert (CURLE_OK ==
                  curl_easy_setopt (eh,
                                    CURLOPT_CUSTOMREQUEST,
                                    "PUT"));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   dh->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (dh->json_enc)));
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&dh->ctx,
+                           eh,
+                           deposit_confirmation_obj))
+  {
+    GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (deposit_confirmation_obj);
+    GNUNET_free (dh->url);
+    GNUNET_free (dh);
+    return NULL;
+  }
+  json_decref (deposit_confirmation_obj);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "URL for deposit-confirmation: `%s'\n",
+              dh->url);
   ctx = MAH_handle_to_context (auditor);
   dh->job = GNUNET_CURL_job_add (ctx,
                                 eh,
@@ -383,7 +384,7 @@ TALER_AUDITOR_deposit_confirmation_cancel (struct 
TALER_AUDITOR_DepositConfirmat
     deposit_confirmation->job = NULL;
   }
   GNUNET_free (deposit_confirmation->url);
-  GNUNET_free (deposit_confirmation->json_enc);
+  TEAH_curl_easy_post_finished (&deposit_confirmation->ctx);
   GNUNET_free (deposit_confirmation);
 }
 
diff --git a/src/lib/auditor_api_handle.c b/src/lib/auditor_api_handle.c
index 70bf6f71..870eed83 100644
--- a/src/lib/auditor_api_handle.c
+++ b/src/lib/auditor_api_handle.c
@@ -15,7 +15,7 @@
   <http://www.gnu.org/licenses/>
 */
 /**
- * @file auditor-lib/auditor_api_handle.c
+ * @file lib/auditor_api_handle.c
  * @brief Implementation of the "handle" component of the auditor's HTTP API
  * @author Sree Harsha Totakura <address@hidden>
  * @author Christian Grothoff
@@ -462,6 +462,16 @@ TALER_AUDITOR_connect (struct GNUNET_CURL_Context *ctx,
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Connecting to auditor at URL `%s'.\n",
               url);
+  /* Disable 100 continue processing */
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CURL_append_header (ctx,
+                                           "Expect:"));
+#if COMPRESS_BODIES
+  /* Tell auditor we compress bodies */
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CURL_append_header (ctx,
+                                           "Content-encoding: deflate"));
+#endif
   auditor = GNUNET_new (struct TALER_AUDITOR_Handle);
   auditor->ctx = ctx;
   auditor->url = GNUNET_strdup (url);
diff --git a/src/lib/auditor_api_handle.h b/src/lib/auditor_api_handle.h
index c3c73f5c..c053cbbc 100644
--- a/src/lib/auditor_api_handle.h
+++ b/src/lib/auditor_api_handle.h
@@ -22,7 +22,7 @@
 #include "platform.h"
 #include <gnunet/gnunet_curl_lib.h>
 #include "taler_auditor_service.h"
-
+#include "teah_common.h"
 
 /**
  * Get the context of a auditor.
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 6b0aa6ff..a9c6e16c 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -342,9 +342,8 @@ TALER_EXCHANGE_get_exchange_signing_key_info (const struct 
TALER_EXCHANGE_Keys *
     const struct TALER_EXCHANGE_SigningPublicKey *spk;
 
     spk = &keys->sign_keys[i];
-    if (0 == memcmp (exchange_pub,
-                    &spk->key,
-                    sizeof (struct TALER_ExchangePublicKeyP)))
+    if (0 == GNUNET_memcmp (exchange_pub,
+                            &spk->key))
       return spk;
   }
   return NULL;
diff --git a/src/lib/exchange_api_curl_defaults.c 
b/src/lib/exchange_api_curl_defaults.c
index 3ac1dfdb..57fae166 100644
--- a/src/lib/exchange_api_curl_defaults.c
+++ b/src/lib/exchange_api_curl_defaults.c
@@ -49,11 +49,9 @@ TEL_curl_easy_get (const char *url)
                  curl_easy_setopt (eh,
                                    CURLOPT_FOLLOWLOCATION,
                                    1L));
-#ifdef CURLOPT_TCP_FASTOPEN
   GNUNET_assert (CURLE_OK ==
                  curl_easy_setopt (eh,
                                    CURLOPT_TCP_FASTOPEN,
                                    1L));
-#endif
   return eh;
 }
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index 3f72ad95..b99c7a93 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -60,9 +60,10 @@ struct TALER_EXCHANGE_DepositHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Handle for the request.
@@ -359,6 +360,7 @@ handle_deposit_finished (void *cls,
  * @param h_contract_terms hash of the contact of the merchant with the 
customer (further details are never disclosed to the exchange)
  * @param coin_pub coin’s public key
  * @param denom_pub denomination key with which the coin is signed
+ * @param denom_pub_hash hash of @a denom_pub
  * @param denom_sig exchange’s unblinded signature of the coin
  * @param timestamp timestamp when the deposit was finalized
  * @param merchant_pub the public key of the merchant (used to identify the 
merchant for refund requests)
@@ -374,6 +376,7 @@ verify_signatures (const struct 
TALER_EXCHANGE_DenomPublicKey *dki,
                    const struct TALER_CoinSpendPublicKeyP *coin_pub,
                    const struct TALER_DenominationSignature *denom_sig,
                    const struct TALER_DenominationPublicKey *denom_pub,
+                   const struct GNUNET_HashCode *denom_pub_hash,
                    struct GNUNET_TIME_Absolute timestamp,
                    const struct TALER_MerchantPublicKeyP *merchant_pub,
                    struct GNUNET_TIME_Absolute refund_deadline,
@@ -414,10 +417,11 @@ verify_signatures (const struct 
TALER_EXCHANGE_DenomPublicKey *dki,
 
   /* check coin signature */
   coin_info.coin_pub = *coin_pub;
-  coin_info.denom_pub = *denom_pub;
+  coin_info.denom_pub_hash = *denom_pub_hash;
   coin_info.denom_sig = *denom_sig;
   if (GNUNET_YES !=
-      TALER_test_coin_valid (&coin_info))
+      TALER_test_coin_valid (&coin_info,
+                             denom_pub))
   {
     GNUNET_break_op (0);
     TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
@@ -489,6 +493,7 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle 
*exchange,
   json_t *deposit_obj;
   CURL *eh;
   struct GNUNET_HashCode h_wire;
+  struct GNUNET_HashCode denom_pub_hash;
   struct TALER_Amount amount_without_fee;
 
   (void) GNUNET_TIME_round_abs (&wire_deadline);
@@ -512,6 +517,8 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle 
*exchange,
                 TALER_amount_subtract (&amount_without_fee,
                                        amount,
                                        &dki->fee_deposit));
+  GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
+                                     &denom_pub_hash);
   if (GNUNET_OK !=
       verify_signatures (dki,
                          amount,
@@ -520,6 +527,7 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle 
*exchange,
                          coin_pub,
                          denom_sig,
                          denom_pub,
+                         &denom_pub_hash,
                          timestamp,
                          merchant_pub,
                          refund_deadline,
@@ -541,7 +549,7 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle 
*exchange,
                            "H_wire", GNUNET_JSON_from_data_auto (&h_wire),
                            "h_contract_terms", GNUNET_JSON_from_data_auto 
(h_contract_terms),
                            "coin_pub", GNUNET_JSON_from_data_auto (coin_pub),
-                           "denom_pub", GNUNET_JSON_from_rsa_public_key 
(denom_pub->rsa_public_key),
+                           "denom_pub_hash", GNUNET_JSON_from_data_auto 
(&denom_pub_hash),
                            "ub_sig", GNUNET_JSON_from_rsa_signature 
(denom_sig->rsa_signature),
                            "timestamp", GNUNET_JSON_from_time_abs (timestamp),
                            "merchant_pub", GNUNET_JSON_from_data_auto 
(merchant_pub),
@@ -574,21 +582,22 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle 
*exchange,
   dh->coin_value = dki->value;
 
   eh = TEL_curl_easy_get (dh->url);
-  GNUNET_assert (NULL != (dh->json_enc =
-                          json_dumps (deposit_obj,
-                                      JSON_COMPACT)));
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&dh->ctx,
+                           eh,
+                           deposit_obj))
+  {
+    GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (deposit_obj);
+    GNUNET_free (dh->url);
+    GNUNET_free (dh);
+    return NULL;
+  }
   json_decref (deposit_obj);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for deposit: `%s'\n",
               dh->url);
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   dh->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (dh->json_enc)));
   ctx = TEAH_handle_to_context (exchange);
   dh->job = GNUNET_CURL_job_add (ctx,
                                 eh,
@@ -614,7 +623,7 @@ TALER_EXCHANGE_deposit_cancel (struct 
TALER_EXCHANGE_DepositHandle *deposit)
     deposit->job = NULL;
   }
   GNUNET_free (deposit->url);
-  GNUNET_free (deposit->json_enc);
+  TEAH_curl_easy_post_finished (&deposit->ctx);
   GNUNET_free (deposit);
 }
 
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 986bcc4c..0f3cfe0a 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -33,6 +33,7 @@
 #include "exchange_api_handle.h"
 #include "exchange_api_curl_defaults.h"
 #include "backoff.h"
+#include "teah_common.h"
 
 /**
  * Which revision of the Taler protocol is implemented
@@ -214,6 +215,17 @@ struct TALER_EXCHANGE_Handle
    */
   enum ExchangeHandleState state;
 
+  /**
+   * If GNUNET_YES, use fake now given by the user, in
+   * request of "/keys".
+   */
+  int with_now;
+
+  /**
+   * Fake now given by the user.
+   */
+  struct GNUNET_TIME_Absolute now;
+
 };
 
 
@@ -421,7 +433,7 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey 
*sign_key,
  */
 static int
 parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key,
-                    int check_sigs,
+                     int check_sigs,
                      json_t *denom_key_obj,
                      struct TALER_MasterPublicKeyP *master_key,
                      struct GNUNET_HashContext *hash_context)
@@ -583,9 +595,8 @@ parse_json_auditor (struct 
TALER_EXCHANGE_AuditorInformation *auditor,
     dk_off = UINT_MAX;
     for (unsigned int j=0;j<key_data->num_denom_keys;j++)
     {
-      if (0 == memcmp (&denom_h,
-                       &key_data->denom_keys[j].h_key,
-                       sizeof (struct GNUNET_HashCode)))
+      if (0 == GNUNET_memcmp (&denom_h,
+                              &key_data->denom_keys[j].h_key))
       {
         dk = &key_data->denom_keys[j];
         dk_off = j;
@@ -698,9 +709,8 @@ update_auditors (struct TALER_EXCHANGE_Handle *exchange)
          NULL != a;
          a = a->next)
     {
-      if (0 == memcmp (&auditor->auditor_pub,
-                       &a->auditor_pub,
-                       sizeof (struct TALER_AuditorPublicKeyP)))
+      if (0 == GNUNET_memcmp (&auditor->auditor_pub,
+                              &a->auditor_pub))
       {
         ale = a;
         break;
@@ -745,7 +755,7 @@ TALER_denoms_cmp (struct TALER_EXCHANGE_DenomPublicKey 
*denom1,
     (denom1->key.rsa_public_key,
      denom2->key.rsa_public_key))
     return 1;
-  
+
   tmp1 = denom1->key.rsa_public_key;
   tmp2 = denom2->key.rsa_public_key;
 
@@ -753,17 +763,16 @@ TALER_denoms_cmp (struct TALER_EXCHANGE_DenomPublicKey 
*denom1,
   denom2->key.rsa_public_key = NULL;
 
   /* Then procede with the rest of the object.  */
-  if (0 != memcmp (denom1,
-                   denom2,
-                   sizeof (struct TALER_EXCHANGE_DenomPublicKey)))
+  if (0 != GNUNET_memcmp (denom1,
+                          denom2))
   {
-    denom1->key.rsa_public_key = tmp1; 
+    denom1->key.rsa_public_key = tmp1;
     denom2->key.rsa_public_key = tmp2;
 
     return 1;
   }
 
-  denom1->key.rsa_public_key = tmp1; 
+  denom1->key.rsa_public_key = tmp1;
   denom2->key.rsa_public_key = tmp2;
 
   return 0;
@@ -979,9 +988,8 @@ decode_keys_json (const json_t *resp_obj,
       {
         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
 
-       if (0 == memcmp (&ai.auditor_pub,
-                        &aix->auditor_pub,
-                        sizeof (struct TALER_AuditorPublicKeyP)))
+       if (0 == GNUNET_memcmp (&ai.auditor_pub,
+                            &aix->auditor_pub))
        {
          found = GNUNET_YES;
           /* Merge denomination key signatures of downloaded /keys into 
existing
@@ -1086,6 +1094,31 @@ void
 TEAH_handle_reset (struct TALER_EXCHANGE_Handle *h);
 
 
+/**
+ * Set the fake now to be used when requesting "/keys".
+ *
+ * @param exchange exchange handle.
+ * @param now fake now to use.  Note: this value will be
+ *        used _until_ its use will be unset via @a TALER_EXCHANGE_unset_now()
+ */
+void
+TALER_EXCHANGE_set_now (struct TALER_EXCHANGE_Handle *exchange,
+                        struct GNUNET_TIME_Absolute now)
+{
+  exchange->with_now = GNUNET_YES;
+  exchange->now = now;
+}
+
+/**
+ * Unset the fake now to be used when requesting "/keys".
+ *
+ * @param exchange exchange handle.
+ */
+void
+TALER_EXCHANGE_unset_now (struct TALER_EXCHANGE_Handle *exchange)
+{
+  exchange->with_now = GNUNET_NO;
+}
 
 /**
  * Let the user set the last valid denomination time manually.
@@ -1537,9 +1570,10 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
 
 
 /**
- * Serialize the latest key data from @a exchange to be persisted on
- * disk (to be used with #TALER_EXCHANGE_OPTION_DATA to more
- * efficiently recover the state).
+ * Serialize the latest key data from @a
+ * exchange to be persisted on disk (to be used with
+ * #TALER_EXCHANGE_OPTION_DATA to more efficiently recover
+ * the state).
  *
  * @param exchange which exchange's key and wire data should be
  *        serialized
@@ -1547,7 +1581,8 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
  *         otherwise JSON object owned by the caller
  */
 json_t *
-TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange)
+TALER_EXCHANGE_serialize_data
+  (struct TALER_EXCHANGE_Handle *exchange)
 {
   const struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
   struct GNUNET_TIME_Absolute now;
@@ -1567,15 +1602,20 @@ TALER_EXCHANGE_serialize_data (struct 
TALER_EXCHANGE_Handle *exchange)
       continue; /* skip keys that have expired */
     signkey = json_pack ("{s:o, s:o, s:o, s:o, s:o}",
                         "key",
-                        GNUNET_JSON_from_data_auto (&sk->key),
+                        GNUNET_JSON_from_data_auto
+                           (&sk->key),
                         "master_sig",
-                        GNUNET_JSON_from_data_auto (&sk->master_sig),
+                        GNUNET_JSON_from_data_auto
+                           (&sk->master_sig),
                         "stamp_start",
-                        GNUNET_JSON_from_time_abs (sk->valid_from),
+                        GNUNET_JSON_from_time_abs
+                           (sk->valid_from),
                         "stamp_expire",
-                        GNUNET_JSON_from_time_abs (sk->valid_until),
+                        GNUNET_JSON_from_time_abs
+                           (sk->valid_until),
                         "stamp_end",
-                        GNUNET_JSON_from_time_abs (sk->valid_legal));
+                        GNUNET_JSON_from_time_abs
+                           (sk->valid_legal));
     if (NULL == signkey)
     {
       GNUNET_break (0);
@@ -1744,6 +1784,12 @@ TALER_EXCHANGE_connect
   GNUNET_break (GNUNET_OK ==
                GNUNET_CURL_append_header (ctx,
                                           "Expect:"));
+#if COMPRESS_BODIES
+  /* Tell exchange we compress bodies */
+  GNUNET_break (GNUNET_OK ==
+               GNUNET_CURL_append_header (ctx,
+                                   "Content-encoding: deflate"));
+#endif
   exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
   exchange->ctx = ctx;
   exchange->url = GNUNET_strdup (url);
@@ -1777,6 +1823,7 @@ TALER_EXCHANGE_connect
 }
 
 
+
 /**
  * Initiate download of /keys from the exchange.
  *
@@ -1788,30 +1835,36 @@ request_keys (void *cls)
   struct TALER_EXCHANGE_Handle *exchange = cls;
   struct KeysRequest *kr;
   CURL *eh;
+  char url[200] = "/keys?";
 
   exchange->retry_task = NULL;
   GNUNET_assert (NULL == exchange->kr);
   kr = GNUNET_new (struct KeysRequest);
   kr->exchange = exchange;
-  if (GNUNET_YES ==
-      TEAH_handle_is_ready (exchange))
-  {
-    char *arg;
 
+  if (GNUNET_YES == TEAH_handle_is_ready (exchange))
+  {
     TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n",
                      GNUNET_STRINGS_absolute_time_to_string 
(exchange->key_data.last_denom_issue_date));
-    GNUNET_asprintf (&arg,
-                     "/keys?last_issue_date=%llu",
-                     (unsigned long long) 
exchange->key_data.last_denom_issue_date.abs_value_us / 1000000LLU);
-    kr->url = TEAH_path_to_url (exchange,
-                                arg);
-    GNUNET_free (arg);
+    sprintf (&url[strlen (url)],
+             "last_issue_date=%llu&",
+             (unsigned long long) 
exchange->key_data.last_denom_issue_date.abs_value_us / 1000000LLU);
   }
-  else
+
+  if (GNUNET_YES == exchange->with_now)
   {
-    kr->url = TEAH_path_to_url (exchange,
-                                "/keys");
+    TALER_LOG_DEBUG ("Faking now to GET /keys: %s\n",
+                     GNUNET_STRINGS_absolute_time_to_string (exchange->now));
+    sprintf (&url[strlen (url)],
+             "now=%llu&",
+             (unsigned long long) exchange->now.abs_value_us / 1000000LLU);
   }
+
+  /* Clean the last '&'/'?' sign that we optimistically put.  */
+  url[strlen (url) - 1] = '\0';
+  kr->url = TEAH_path_to_url (exchange,
+                              url);
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Requesting keys with URL `%s'.\n",
               kr->url);
@@ -1913,9 +1966,8 @@ TALER_EXCHANGE_get_signing_key_details (const struct 
TALER_EXCHANGE_Keys *keys,
   {
     struct TALER_EXCHANGE_SigningPublicKey *spk = &keys->sign_keys[i];
 
-    if (0 == memcmp (pub,
-                    &spk->key,
-                    sizeof (struct TALER_ExchangePublicKeyP)))
+    if (0 == GNUNET_memcmp (pub,
+                            &spk->key))
       return spk;
   }
   return NULL;
@@ -1941,9 +1993,8 @@ TALER_EXCHANGE_test_signing_key (const struct 
TALER_EXCHANGE_Keys *keys,
   for (unsigned int i=0;i<keys->num_sign_keys;i++)
     if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 
* 60 * 1000LL * 1000LL) &&
          (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 
* 60 * 1000LL * 1000LL) &&
-         (0 == memcmp (pub,
-                       &keys->sign_keys[i].key,
-                       sizeof (struct TALER_ExchangePublicKeyP))) )
+         (0 == GNUNET_memcmp (pub,
+                              &keys->sign_keys[i].key)) )
       return GNUNET_OK;
   return GNUNET_SYSERR;
 }
@@ -1994,9 +2045,8 @@ TALER_EXCHANGE_get_denomination_key_by_hash (const struct 
TALER_EXCHANGE_Keys *k
                                              const struct GNUNET_HashCode *hc)
 {
   for (unsigned int i=0;i<keys->num_denom_keys;i++)
-    if (0 == memcmp (hc,
-                     &keys->denom_keys[i].h_key,
-                     sizeof (struct GNUNET_HashCode)))
+    if (0 == GNUNET_memcmp (hc,
+                            &keys->denom_keys[i].h_key))
       return &keys->denom_keys[i];
   return NULL;
 }
diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h
index 2c01e319..6bb3fff2 100644
--- a/src/lib/exchange_api_handle.h
+++ b/src/lib/exchange_api_handle.h
@@ -24,7 +24,7 @@
 #include "taler_auditor_service.h"
 #include "taler_exchange_service.h"
 #include "taler_crypto_lib.h"
-
+#include "teah_common.h"
 
 /**
  * Entry in DLL of auditors used by an exchange.
diff --git a/src/lib/exchange_api_payback.c b/src/lib/exchange_api_payback.c
index 6c1772af..325263d7 100644
--- a/src/lib/exchange_api_payback.c
+++ b/src/lib/exchange_api_payback.c
@@ -49,9 +49,10 @@ struct TALER_EXCHANGE_PaybackHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Denomination key of the coin.
@@ -280,6 +281,7 @@ TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle 
*exchange,
   struct GNUNET_CURL_Context *ctx;
   struct TALER_PaybackRequestPS pr;
   struct TALER_CoinSpendSignatureP coin_sig;
+  struct GNUNET_HashCode h_denom_pub;
   json_t *payback_obj;
   CURL *eh;
 
@@ -289,6 +291,8 @@ TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle 
*exchange,
   pr.purpose.size = htonl (sizeof (struct TALER_PaybackRequestPS));
   GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv,
                                       &pr.coin_pub.eddsa_pub);
+  GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key,
+                                     &h_denom_pub);
   pr.h_denom_pub = pk->h_key;
   pr.coin_blind = ps->blinding_key;
   GNUNET_assert (GNUNET_OK ==
@@ -299,7 +303,7 @@ TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle 
*exchange,
   payback_obj = json_pack ("{s:o, s:o," /* denom pub/sig */
                            " s:o, s:o," /* coin pub/sig */
                            " s:o}", /* coin_bks */
-                           "denom_pub", GNUNET_JSON_from_rsa_public_key 
(pk->key.rsa_public_key),
+                           "denom_pub_hash", GNUNET_JSON_from_data_auto 
(&h_denom_pub),
                            "denom_sig", GNUNET_JSON_from_rsa_signature 
(denom_sig->rsa_signature),
                            "coin_pub", GNUNET_JSON_from_data_auto 
(&pr.coin_pub),
                            "coin_sig", GNUNET_JSON_from_data_auto (&coin_sig),
@@ -318,29 +322,23 @@ TALER_EXCHANGE_payback (struct TALER_EXCHANGE_Handle 
*exchange,
   ph->cb = payback_cb;
   ph->cb_cls = payback_cb_cls;
   ph->url = TEAH_path_to_url (exchange, "/payback");
-
-  ph->json_enc = json_dumps (payback_obj,
-                             JSON_COMPACT);
-  json_decref (payback_obj);
-  if (NULL == ph->json_enc)
+  eh = TEL_curl_easy_get (ph->url);
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&ph->ctx,
+                           eh,
+                           payback_obj))
   {
     GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (payback_obj);
     GNUNET_free (ph->url);
     GNUNET_free (ph);
     return NULL;
   }
-  eh = TEL_curl_easy_get (ph->url);
+  json_decref (payback_obj);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for payback: `%s'\n",
               ph->url);
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   ph->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (ph->json_enc)));
   ctx = TEAH_handle_to_context (exchange);
   ph->job = GNUNET_CURL_job_add (ctx,
                                 eh,
@@ -366,7 +364,7 @@ TALER_EXCHANGE_payback_cancel (struct 
TALER_EXCHANGE_PaybackHandle *ph)
     ph->job = NULL;
   }
   GNUNET_free (ph->url);
-  GNUNET_free (ph->json_enc);
+  TEAH_curl_easy_post_finished (&ph->ctx);
   GNUNET_free (ph);
 }
 
diff --git a/src/lib/exchange_api_refresh.c b/src/lib/exchange_api_refresh.c
index 230f445e..30025d77 100644
--- a/src/lib/exchange_api_refresh.c
+++ b/src/lib/exchange_api_refresh.c
@@ -834,9 +834,10 @@ struct TALER_EXCHANGE_RefreshMeltHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Handle for the request.
@@ -1151,6 +1152,7 @@ TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle 
*exchange,
   struct MeltData *md;
   struct TALER_CoinSpendSignatureP confirm_sig;
   struct TALER_RefreshMeltCoinAffirmationPS melt;
+  struct GNUNET_HashCode h_denom_pub;
 
   GNUNET_assert (GNUNET_YES ==
                 TEAH_handle_is_ready (exchange));
@@ -1174,11 +1176,13 @@ TALER_EXCHANGE_refresh_melt (struct 
TALER_EXCHANGE_Handle *exchange,
   GNUNET_CRYPTO_eddsa_sign (&md->melted_coin.coin_priv.eddsa_priv,
                             &melt.purpose,
                             &confirm_sig.eddsa_signature);
+  GNUNET_CRYPTO_rsa_public_key_hash (md->melted_coin.pub_key.rsa_public_key,
+                                     &h_denom_pub);
   melt_obj = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}",
                         "coin_pub",
                         GNUNET_JSON_from_data_auto (&melt.coin_pub),
-                        "denom_pub",
-                        GNUNET_JSON_from_rsa_public_key 
(md->melted_coin.pub_key.rsa_public_key),
+                        "denom_pub_hash",
+                        GNUNET_JSON_from_data_auto (&h_denom_pub),
                         "denom_sig",
                         GNUNET_JSON_from_rsa_signature 
(md->melted_coin.sig.rsa_signature),
                         "confirm_sig",
@@ -1203,18 +1207,19 @@ TALER_EXCHANGE_refresh_melt (struct 
TALER_EXCHANGE_Handle *exchange,
   rmh->url = TEAH_path_to_url (exchange,
                               "/refresh/melt");
   eh = TEL_curl_easy_get (rmh->url);
-  GNUNET_assert (NULL != (rmh->json_enc =
-                          json_dumps (melt_obj,
-                                      JSON_COMPACT)));
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&rmh->ctx,
+                           eh,
+                           melt_obj))
+  {
+    GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (melt_obj);
+    GNUNET_free (rmh->url);
+    GNUNET_free (rmh);
+    return NULL;
+  }
   json_decref (melt_obj);
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   rmh->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (rmh->json_enc)));
   ctx = TEAH_handle_to_context (exchange);
   rmh->job = GNUNET_CURL_job_add (ctx,
                           eh,
@@ -1242,7 +1247,7 @@ TALER_EXCHANGE_refresh_melt_cancel (struct 
TALER_EXCHANGE_RefreshMeltHandle *rmh
   free_melt_data (rmh->md); /* does not free 'md' itself */
   GNUNET_free (rmh->md);
   GNUNET_free (rmh->url);
-  GNUNET_free (rmh->json_enc);
+  TEAH_curl_easy_post_finished (&rmh->ctx);
   GNUNET_free (rmh);
 }
 
@@ -1267,9 +1272,10 @@ struct TALER_EXCHANGE_RefreshRevealHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Handle for the request.
@@ -1631,18 +1637,19 @@ TALER_EXCHANGE_refresh_reveal (struct 
TALER_EXCHANGE_Handle *exchange,
                               "/refresh/reveal");
 
   eh = TEL_curl_easy_get (rrh->url);
-  GNUNET_assert (NULL != (rrh->json_enc =
-                          json_dumps (reveal_obj,
-                                      JSON_COMPACT)));
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&rrh->ctx,
+                           eh,
+                           reveal_obj))
+  {
+    GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (reveal_obj);
+    GNUNET_free (rrh->url);
+    GNUNET_free (rrh);
+    return NULL;
+  }
   json_decref (reveal_obj);
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   rrh->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (rrh->json_enc)));
   ctx = TEAH_handle_to_context (rrh->exchange);
   rrh->job = GNUNET_CURL_job_add (ctx,
                                   eh,
@@ -1668,7 +1675,7 @@ TALER_EXCHANGE_refresh_reveal_cancel (struct 
TALER_EXCHANGE_RefreshRevealHandle
     rrh->job = NULL;
   }
   GNUNET_free (rrh->url);
-  GNUNET_free (rrh->json_enc);
+  TEAH_curl_easy_post_finished (&rrh->ctx);
   free_melt_data (rrh->md); /* does not free 'md' itself */
   GNUNET_free (rrh->md);
   GNUNET_free (rrh);
diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c
index 75ebdc4e..14221317 100644
--- a/src/lib/exchange_api_refund.c
+++ b/src/lib/exchange_api_refund.c
@@ -49,9 +49,10 @@ struct TALER_EXCHANGE_RefundHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Handle for the request.
@@ -368,21 +369,22 @@ refund_obj = json_pack ("{s:o, s:o," /* amount/fee */
                      refund_fee);
 
   eh = TEL_curl_easy_get (rh->url);
-  GNUNET_assert (NULL != (rh->json_enc =
-                          json_dumps (refund_obj,
-                                      JSON_COMPACT)));
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&rh->ctx,
+                           eh,
+                           refund_obj))
+  {
+    GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (refund_obj);
+    GNUNET_free (rh->url);
+    GNUNET_free (rh);
+    return NULL;
+  }
   json_decref (refund_obj);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "URL for refund: `%s'\n",
               rh->url);
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   rh->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (rh->json_enc)));
   ctx = TEAH_handle_to_context (exchange);
   rh->job = GNUNET_CURL_job_add (ctx,
                                 eh,
@@ -408,7 +410,7 @@ TALER_EXCHANGE_refund_cancel (struct 
TALER_EXCHANGE_RefundHandle *refund)
     refund->job = NULL;
   }
   GNUNET_free (refund->url);
-  GNUNET_free (refund->json_enc);
+  TEAH_curl_easy_post_finished (&refund->ctx);
   GNUNET_free (refund);
 }
 
diff --git a/src/lib/exchange_api_reserve.c b/src/lib/exchange_api_reserve.c
index 9c0ff6d7..ae0bd01d 100644
--- a/src/lib/exchange_api_reserve.c
+++ b/src/lib/exchange_api_reserve.c
@@ -187,8 +187,8 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle 
*exchange,
       struct GNUNET_JSON_Specification withdraw_spec[] = {
         GNUNET_JSON_spec_fixed_auto ("reserve_sig",
                                      &sig),
-       TALER_JSON_spec_amount_nbo ("withdraw_fee",
-                                   &withdraw_purpose.withdraw_fee),
+        TALER_JSON_spec_amount_nbo ("withdraw_fee",
+                                    &withdraw_purpose.withdraw_fee),
         GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
                                      &withdraw_purpose.h_denomination_pub),
         GNUNET_JSON_spec_fixed_auto ("h_coin_envelope",
@@ -238,9 +238,8 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle 
*exchange,
                           &uuid[uuid_off]);
       for (i=0;i<uuid_off;i++)
       {
-        if (0 == memcmp (&uuid[uuid_off],
-                         &uuid[i],
-                         sizeof (struct GNUNET_HashCode)))
+        if (0 == GNUNET_memcmp (&uuid[uuid_off],
+                                &uuid[i]))
         {
           GNUNET_break_op (0);
           GNUNET_JSON_parse_free (withdraw_spec);
@@ -678,9 +677,10 @@ struct TALER_EXCHANGE_ReserveWithdrawHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Handle for the request.
@@ -1002,6 +1002,7 @@ reserve_withdraw_internal (struct TALER_EXCHANGE_Handle 
*exchange,
   struct GNUNET_CURL_Context *ctx;
   json_t *withdraw_obj;
   CURL *eh;
+  struct GNUNET_HashCode h_denom_pub;
 
   wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveWithdrawHandle);
   wsh->exchange = exchange;
@@ -1010,9 +1011,11 @@ reserve_withdraw_internal (struct TALER_EXCHANGE_Handle 
*exchange,
   wsh->pk = pk;
   wsh->reserve_pub = *reserve_pub;
   wsh->c_hash = pd->c_hash;
-  withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub and coin_ev */
+  GNUNET_CRYPTO_rsa_public_key_hash (pk->key.rsa_public_key,
+                                     &h_denom_pub);
+  withdraw_obj = json_pack ("{s:o, s:o," /* denom_pub_hash and coin_ev */
                             " s:o, s:o}",/* reserve_pub and reserve_sig */
-                            "denom_pub", GNUNET_JSON_from_rsa_public_key 
(pk->key.rsa_public_key),
+                            "denom_pub_hash", GNUNET_JSON_from_data_auto 
(&h_denom_pub),
                             "coin_ev", GNUNET_JSON_from_data (pd->coin_ev,
                                                               
pd->coin_ev_size),
                             "reserve_pub", GNUNET_JSON_from_data_auto 
(reserve_pub),
@@ -1020,25 +1023,26 @@ reserve_withdraw_internal (struct TALER_EXCHANGE_Handle 
*exchange,
   if (NULL == withdraw_obj)
   {
     GNUNET_break (0);
+    GNUNET_free (wsh);
     return NULL;
   }
 
   wsh->ps = *ps;
   wsh->url = TEAH_path_to_url (exchange, "/reserve/withdraw");
-
   eh = TEL_curl_easy_get (wsh->url);
-  GNUNET_assert (NULL != (wsh->json_enc =
-                          json_dumps (withdraw_obj,
-                                      JSON_COMPACT)));
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&wsh->ctx,
+                           eh,
+                           withdraw_obj))
+  {
+    GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (withdraw_obj);
+    GNUNET_free (wsh->url);
+    GNUNET_free (wsh);
+    return NULL;
+  }
   json_decref (withdraw_obj);
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   wsh->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (wsh->json_enc)));
   ctx = TEAH_handle_to_context (exchange);
   wsh->job = GNUNET_CURL_job_add (ctx,
                           eh,
@@ -1197,7 +1201,7 @@ TALER_EXCHANGE_reserve_withdraw_cancel (struct 
TALER_EXCHANGE_ReserveWithdrawHan
     sign->job = NULL;
   }
   GNUNET_free (sign->url);
-  GNUNET_free (sign->json_enc);
+  TEAH_curl_easy_post_finished (&sign->ctx);
   GNUNET_free (sign);
 }
 
diff --git a/src/lib/exchange_api_track_transaction.c 
b/src/lib/exchange_api_track_transaction.c
index 0942ce84..67efd77a 100644
--- a/src/lib/exchange_api_track_transaction.c
+++ b/src/lib/exchange_api_track_transaction.c
@@ -49,9 +49,10 @@ struct TALER_EXCHANGE_TrackTransactionHandle
   char *url;
 
   /**
-   * JSON encoding of the request to POST.
+   * Context for #TEH_curl_easy_post(). Keeps the data that must
+   * persist for Curl to make the upload.
    */
-  char *json_enc;
+  struct TEAH_PostContext ctx;
 
   /**
    * Handle for the request.
@@ -322,18 +323,19 @@ TALER_EXCHANGE_track_transaction (struct 
TALER_EXCHANGE_Handle *exchange,
   dwh->depconf.coin_pub = *coin_pub;
 
   eh = TEL_curl_easy_get (dwh->url);
-  GNUNET_assert (NULL != (dwh->json_enc =
-                          json_dumps (deposit_wtid_obj,
-                                      JSON_COMPACT)));
+  if (GNUNET_OK !=
+      TEAH_curl_easy_post (&dwh->ctx,
+                           eh,
+                           deposit_wtid_obj))
+  {
+    GNUNET_break (0);
+    curl_easy_cleanup (eh);
+    json_decref (deposit_wtid_obj);
+    GNUNET_free (dwh->url);
+    GNUNET_free (dwh);
+    return NULL;
+  }
   json_decref (deposit_wtid_obj);
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDS,
-                                   dwh->json_enc));
-  GNUNET_assert (CURLE_OK ==
-                 curl_easy_setopt (eh,
-                                   CURLOPT_POSTFIELDSIZE,
-                                   strlen (dwh->json_enc)));
   ctx = TEAH_handle_to_context (exchange);
   dwh->job = GNUNET_CURL_job_add (ctx,
                           eh,
@@ -359,9 +361,9 @@ TALER_EXCHANGE_track_transaction_cancel (struct 
TALER_EXCHANGE_TrackTransactionH
     dwh->job = NULL;
   }
   GNUNET_free (dwh->url);
-  GNUNET_free (dwh->json_enc);
+  TEAH_curl_easy_post_finished (&dwh->ctx);
   GNUNET_free (dwh);
 }
 
 
-/* end of exchange_api_deposit_wtid.c */
+/* end of exchange_api_track_transaction.c */
diff --git a/src/lib/teah_common.c b/src/lib/teah_common.c
new file mode 100644
index 00000000..8f994ef3
--- /dev/null
+++ b/src/lib/teah_common.c
@@ -0,0 +1,105 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2019 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 Foundation; either version 3, or (at your
+  option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/teah_common.c
+ * @brief Helper routines shared by libtalerexchange and libtalerauditor
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "teah_common.h"
+
+#if COMPRESS_BODIES
+#include <zlib.h>
+#endif
+
+
+/**
+ * Add the @a body as POST data to the easy handle in
+ * @a ctx.
+ *
+ * @param ctx[in,out] a request context (updated)
+ * @param eh easy handle to use
+ * @param body JSON body to add to @e ctx
+ * @return #GNUNET_OK on success #GNUNET_SYSERR on failure
+ */
+int
+TEAH_curl_easy_post (struct TEAH_PostContext *ctx,
+                     CURL *eh,
+                     const json_t *body)
+{
+  char *str;
+  size_t slen;
+
+  str = json_dumps (body,
+                    JSON_COMPACT);
+  if (NULL == str)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  slen = strlen (str);
+#if COMPRESS_BODIES
+  {
+    Bytef *cbuf;
+    uLongf cbuf_size;
+    int ret;
+
+    cbuf_size = compressBound (slen);
+    cbuf = GNUNET_malloc (cbuf_size);
+    ret = compress (cbuf,
+                    &cbuf_size,
+                    (const Bytef *) str,
+                    slen);
+    if (Z_OK != ret)
+    {
+      /* compression failed!? */
+      GNUNET_break (0);
+      GNUNET_free (cbuf);
+      return GNUNET_SYSERR;
+    }
+    free (str);
+    slen = (size_t) cbuf_size;
+    ctx->json_enc = (char *) cbuf;
+  }
+#else
+  ctx->json_enc = str;
+#endif
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_POSTFIELDS,
+                                   ctx->json_enc));
+  GNUNET_assert (CURLE_OK ==
+                 curl_easy_setopt (eh,
+                                   CURLOPT_POSTFIELDSIZE,
+                                   slen));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Free the data in @a ctx.
+ *
+ * @param ctx[in] a request context (updated)
+ */
+void
+TEAH_curl_easy_post_finished (struct TEAH_PostContext *ctx)
+{
+  GNUNET_free_non_null (ctx->json_enc);
+}
diff --git a/src/lib/teah_common.h b/src/lib/teah_common.h
new file mode 100644
index 00000000..66937a26
--- /dev/null
+++ b/src/lib/teah_common.h
@@ -0,0 +1,74 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2019 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 Foundation; either version 3, or (at your
+  option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public
+  License along with TALER; see the file COPYING.  If not, see
+  <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/teah_common.h
+ * @brief Helper routines shared by libtalerexchange and libtalerauditor
+ * @author Christian Grothoff
+ */
+#ifndef TEAH_COMMON_H
+#define TEAH_COMMON_H
+
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_json_lib.h"
+
+/**
+ * Should we compress PUT/POST bodies with 'deflate' encoding?
+ */
+#define COMPRESS_BODIES 0
+
+/**
+ * State used for #TEAL_curl_easy_post() and
+ * #TEAL_curl_easy_post_finished().
+ */
+struct TEAH_PostContext
+{
+  /**
+   * JSON encoding of the request to POST.
+   */
+  char *json_enc;
+
+};
+
+
+/**
+ * Add the @a body as POST data to the easy handle in
+ * @a ctx.
+ *
+ * @param ctx[in,out] a request context (updated)
+ * @param eh easy handle to use
+ * @param body JSON body to add to @e ctx
+ * @return #GNUNET_OK on success #GNUNET_SYSERR on failure
+ */
+int
+TEAH_curl_easy_post (struct TEAH_PostContext *ctx,
+                     CURL *eh,
+                     const json_t *body);
+
+
+/**
+ * Free the data in @a ctx.
+ *
+ * @param ctx[in] a request context (updated)
+ */
+void
+TEAH_curl_easy_post_finished (struct TEAH_PostContext *ctx);
+
+
+
+#endif
diff --git a/src/lib/test_exchange_api_interpreter_on-off.c 
b/src/lib/test_exchange_api_interpreter_on-off.c
old mode 100755
new mode 100644
diff --git a/src/lib/test_exchange_api_keys_cherry_picking.conf 
b/src/lib/test_exchange_api_keys_cherry_picking.conf
index e8473d46..afa003fa 100644
--- a/src/lib/test_exchange_api_keys_cherry_picking.conf
+++ b/src/lib/test_exchange_api_keys_cherry_picking.conf
@@ -101,6 +101,15 @@ WIRE-FEE-2023 = EUR:0.01
 WIRE-FEE-2024 = EUR:0.01
 WIRE-FEE-2025 = EUR:0.01
 WIRE-FEE-2026 = EUR:0.01
+WIRE-FEE-2027 = EUR:0.01
+WIRE-FEE-2028 = EUR:0.01
+WIRE-FEE-2029 = EUR:0.01
+WIRE-FEE-2030 = EUR:0.01
+WIRE-FEE-2031 = EUR:0.01
+WIRE-FEE-2032 = EUR:0.01
+WIRE-FEE-2033 = EUR:0.01
+WIRE-FEE-2034 = EUR:0.01
+WIRE-FEE-2035 = EUR:0.01
 
 CLOSING-FEE-2017 = EUR:0.01
 CLOSING-FEE-2018 = EUR:0.01
@@ -112,6 +121,16 @@ CLOSING-FEE-2023 = EUR:0.01
 CLOSING-FEE-2024 = EUR:0.01
 CLOSING-FEE-2025 = EUR:0.01
 CLOSING-FEE-2026 = EUR:0.01
+CLOSING-FEE-2027 = EUR:0.01
+CLOSING-FEE-2028 = EUR:0.01
+CLOSING-FEE-2029 = EUR:0.01
+CLOSING-FEE-2030 = EUR:0.01
+CLOSING-FEE-2031 = EUR:0.01
+CLOSING-FEE-2032 = EUR:0.01
+CLOSING-FEE-2033 = EUR:0.01
+CLOSING-FEE-2034 = EUR:0.01
+CLOSING-FEE-2035 = EUR:0.01
+
 
 [fees-sepa]
 # Fees for the forseeable future...
diff --git a/src/lib/test_exchange_api_keys_cherry_picking_new.c 
b/src/lib/test_exchange_api_keys_cherry_picking_new.c
index 4702b29d..e9763bd4 100644
--- a/src/lib/test_exchange_api_keys_cherry_picking_new.c
+++ b/src/lib/test_exchange_api_keys_cherry_picking_new.c
@@ -35,6 +35,7 @@
 #include "taler_fakebank_lib.h"
 #include "taler_testing_lib.h"
 
+
 /**
  * Configuration file we use.  One (big) configuration is used
  * for the various components for this test.
@@ -53,6 +54,37 @@
 #define CONFIG_FILE_EXTENDED_2 \
   "test_exchange_api_keys_cherry_picking_extended_2.conf"
 
+
+#define NDKS_RIGHT_BEFORE_SERIALIZATION 46
+
+/**
+ * Add seconds.
+ *
+ * @param base absolute time to add seconds to.
+ * @param relative number of seconds to add.
+ * @return a new absolute time, modified according to @e relative.
+ */
+#define ADDSECS(base, secs) \
+  GNUNET_TIME_absolute_add \
+    (base, \
+     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+                                    secs))
+
+/**
+ * Subtract seconds.
+ *
+ * @param base absolute time to subtract seconds to.
+ * @param secs relative number of _seconds_ to subtract.
+ * @return a new absolute time, modified according to @e relative.
+ */
+#define SUBSECS(base, secs) \
+  GNUNET_TIME_absolute_subtract \
+    (base, \
+     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+                                    secs))
+#define JAN1971 "1971-01-01"
+#define JAN2030 "2030-01-01"
+
 /**
  * Exchange base URL; mainly purpose is to make the compiler happy.
  */
@@ -64,6 +96,24 @@ static char *exchange_url;
 static char *auditor_url;
 
 /**
+ * Wrapper around the time parser.
+ *
+ * @param str human-readable time string.
+ * @return the parsed time from @a str.
+ */
+static struct GNUNET_TIME_Absolute
+TTH_parse_time (const char *str)
+{
+  struct GNUNET_TIME_Absolute ret;
+
+  GNUNET_assert
+    (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_absolute (str,
+                                                         &ret));
+  return ret;
+}
+
+
+/**
  * Main function that will tell the interpreter what commands to
  * run.
  *
@@ -74,60 +124,34 @@ run (void *cls,
      struct TALER_TESTING_Interpreter *is)
 {
   struct TALER_TESTING_Command keys_serialization[] = {
-    TALER_TESTING_cmd_serialize_keys ("serialize-keys"),
-    TALER_TESTING_cmd_connect_with_state ("reconnect-with-state",
-                                          "serialize-keys"),
-    TALER_TESTING_cmd_wire ("verify-/wire-with-serialized-keys",
-                            "x-taler-bank",
-                            NULL,
-                            MHD_HTTP_OK),
+
+    TALER_TESTING_cmd_serialize_keys
+      ("serialize-keys"),
+
+    TALER_TESTING_cmd_connect_with_state
+      ("reconnect-with-state",
+       "serialize-keys"),
+    /**
+     * Make sure we have the same keys situation as
+     * it was before the serialization.
+     */
+    TALER_TESTING_cmd_check_keys_with_now
+      ("check-keys-after-deserialization",
+       4,
+       NDKS_RIGHT_BEFORE_SERIALIZATION,
+       /**
+        * Pretend 5 seconds passed.
+        */
+       ADDSECS (TTH_parse_time (JAN2030),
+                5)),
     /**
-     * This loads a very big lookahead_sign (3500s).
+     * Use one of the deserialized keys.
      */
-    TALER_TESTING_cmd_exec_keyup ("keyup-serialization",
-                                  CONFIG_FILE_EXTENDED_2),
-    TALER_TESTING_cmd_exec_auditor_sign
-      ("auditor-sign-serialization",
-       CONFIG_FILE_EXTENDED_2),
-
-    TALER_TESTING_cmd_sleep ("sleep-serialization",
-                             3),
-    TALER_TESTING_cmd_signal ("reload-keys-serialization",
-                              is->exchanged,
-                              SIGUSR1),
-    TALER_TESTING_cmd_sleep ("sleep-serialization",
-                             3),
-    #if 0
-
-    FIXME: #5672
-    
-    The test below fails on different systems.  Infact, different
-    systems can generate different "anchors" values for their denoms,
-    therefore the fixed value required by the test below (45) is
-    condemned to fail.
-
-    However, this seems to happen only when very big values are
-    used for the "lookahead_sign" value.  Here we use 3500 seconds,
-    and the test breaks.
-
-    A reasonable fix is to allow for some slack in the number of
-    the expected keys.
-
-    TALER_TESTING_cmd_check_keys ("check-freshest-keys",
-                       /* At this point, /keys has been
-                        * downloaded roughly 6 times, so by
-                        * forcing 10 here we make sure we get
-                        * all the new ones.  */
-                                  10, 
-                       /* We use a very high number here to make
-                        * sure the "big" lookahead value got
-                        * respected.  */
-                                  45),
-    #endif
-    TALER_TESTING_cmd_wire ("verify-/wire-with-fresh-keys",
-                            "x-taler-bank",
-                            NULL,
-                            MHD_HTTP_OK),
+    TALER_TESTING_cmd_wire
+      ("verify-/wire-with-serialized-keys",
+       "x-taler-bank",
+       NULL,
+       MHD_HTTP_OK),
 
     TALER_TESTING_cmd_end (),
 
@@ -135,59 +159,66 @@ run (void *cls,
 
   struct TALER_TESTING_Command ordinary_cherry_pick[] = {
 
-    /* Trigger keys reloading from disk.  */
-    TALER_TESTING_cmd_signal ("signal-reaction-1",
-                              is->exchanged,
-                              SIGUSR1),
     /**
-     * 1 DK with 80s spend duration.
+     * 1 DK with 80s withdraw duration, lookahead_sign is 60s
+     * => expect 1 DK.
      */
     TALER_TESTING_cmd_check_keys ("check-keys-1",
                                   1, /* generation */
                                   1),
-
-    TALER_TESTING_cmd_sleep ("sleep",
-                             10),
-
     /**
-     * We set lookahead_sign to 90s.
+     * The far-future now will cause "keyup" to start a fresh
+     * key set.  The new KS will have only one key, because the
+     * current lookahead_sign == 60 seconds and the key's withdraw
+     * duration is 80 seconds.
      */
-    TALER_TESTING_cmd_exec_keyup ("keyup-2",
-                                  CONFIG_FILE_EXTENDED),
-    TALER_TESTING_cmd_exec_auditor_sign ("sign-keys-1",
-                                         CONFIG_FILE_EXTENDED),
-
-    TALER_TESTING_cmd_signal ("trigger-keys-reload-1",
-                              is->exchanged,
-                              SIGUSR1),
-    /**
-     * First DK has still 70s of remaining life
-     * (duration_withdraw), so it's not enough to cover the new
-     * 90s window, so a new one should be created.
-     * Total 2 DKs.
+    TALER_TESTING_cmd_exec_keyup_with_now
+      ("keyup-1",
+       CONFIG_FILE,
+       TTH_parse_time (JAN2030)),
+
+     /**
+     * Should return 1 new key, + the original one.  NOTE: the
+     * original DK will never be 'cancelled' as for the current
+     * libtalerexchange logic, so it must always be counted.
      */
-    TALER_TESTING_cmd_check_keys ("check-keys-2",
-                                  2, /* generation */
-                                  2),
-
-    TALER_TESTING_cmd_sleep ("sleep",
-                             20),
-    TALER_TESTING_cmd_exec_keyup ("keyup-3",
-                                  CONFIG_FILE_EXTENDED),
-    TALER_TESTING_cmd_exec_auditor_sign ("sign-keys-2",
-                                         CONFIG_FILE),
-    TALER_TESTING_cmd_signal ("trigger-keys-reload-2",
-                              is->exchanged,
-                              SIGUSR1),
+    TALER_TESTING_cmd_check_keys_with_now
+      ("check-keys-2",
+       2, /* generation */
+       2,
+       TTH_parse_time (JAN2030)),
+
+    TALER_TESTING_cmd_exec_keyup_with_now
+      ("keyup-3",
+       CONFIG_FILE_EXTENDED_2,
+       /* Taking care of not using a 'now' that equals the
+        * last DK timestamp, otherwise it would get silently
+        * overridden.  */
+       ADDSECS (TTH_parse_time (JAN2030),
+                10)),
 
     /**
-     * First DK has 50s of remaining life (duration_withdraw).
-     * The second DK has ~60s of remaining life, therefore two
-     * keys should be (still) returned.
+     * Expected number of DK:
+     *
+     * 3500 (the lookaeahd_sign time frame, in seconds)
+     * - 69 (how many seconds are covered by the latest DK)
+     * ----
+     * 3431
+     * / 79 (how many seconds each DK will cover)
+     * ----
+     *   44 (rounded up)
+     *  + 2 (old DKs already stored locally: 1 from the
+     *       very initial setup, and 1 from the 'keyup-1' CMD)
+     * ----
+     *   46
      */
-    TALER_TESTING_cmd_check_keys ("check-keys-3",
-                                  3,
-                                  2),
+
+    TALER_TESTING_cmd_check_keys_with_now
+      ("check-keys-3",
+       3, 
+       NDKS_RIGHT_BEFORE_SERIALIZATION,
+       TTH_parse_time (JAN2030)),
+
     TALER_TESTING_cmd_end ()
   };
   struct TALER_TESTING_Command commands[] = {
diff --git a/src/lib/test_exchange_api_twisted.c 
b/src/lib/test_exchange_api_twisted.c
index 1c530058..74d84820 100644
--- a/src/lib/test_exchange_api_twisted.c
+++ b/src/lib/test_exchange_api_twisted.c
@@ -26,15 +26,15 @@
  */
 
 #include "platform.h"
-#include <taler/taler_util.h>
-#include <taler/taler_signatures.h>
-#include <taler/taler_exchange_service.h>
-#include <taler/taler_json_lib.h>
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
 #include <gnunet/gnunet_util_lib.h>
 #include <microhttpd.h>
-#include <taler/taler_bank_service.h>
-#include <taler/taler_fakebank_lib.h>
-#include <taler/taler_testing_lib.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
 #include <taler/taler_twister_testing_lib.h>
 #include <taler/taler_twister_service.h>
 
@@ -144,8 +144,6 @@ static void
 run (void *cls,
      struct TALER_TESTING_Interpreter *is)
 {
-
-
   /**
    * This batch aims to trigger the 409 Conflict
    * response from a refresh-reveal operation.
diff --git a/src/lib/testing_api_cmd_bank_check.c 
b/src/lib/testing_api_cmd_bank_check.c
index 265cba17..67dbc0e1 100644
--- a/src/lib/testing_api_cmd_bank_check.c
+++ b/src/lib/testing_api_cmd_bank_check.c
@@ -335,12 +335,13 @@ check_bank_empty_traits (void *cls,
 struct TALER_TESTING_Command
 TALER_TESTING_cmd_check_bank_empty (const char *label)
 {
-  struct TALER_TESTING_Command cmd;
 
-  cmd.label = label;
-  cmd.run = &check_bank_empty_run;
-  cmd.cleanup = &check_bank_empty_cleanup;
-  cmd.traits = &check_bank_empty_traits;
+  struct TALER_TESTING_Command cmd = {
+    .label = label,
+    .run = &check_bank_empty_run,
+    .cleanup = &check_bank_empty_cleanup,
+    .traits = &check_bank_empty_traits
+  };
   
   return cmd;
 }
@@ -364,16 +365,17 @@ TALER_TESTING_cmd_check_bank_transfer_with_ref
 {
 
   struct BankCheckState *bcs;
-  struct TALER_TESTING_Command cmd;
 
   bcs = GNUNET_new (struct BankCheckState);
   bcs->deposit_reference = deposit_reference;
 
-  cmd.label = label;
-  cmd.cls = bcs;
-  cmd.run = &check_bank_transfer_run;
-  cmd.cleanup = &check_bank_transfer_cleanup;
-  cmd.traits = &check_bank_transfer_traits;
+  struct TALER_TESTING_Command cmd = {
+    .label = label,
+    .cls = bcs,
+    .run = &check_bank_transfer_run,
+    .cleanup = &check_bank_transfer_cleanup,
+    .traits = &check_bank_transfer_traits
+  };
 
   return cmd;
 }
diff --git a/src/lib/testing_api_cmd_check_keys.c 
b/src/lib/testing_api_cmd_check_keys.c
index 45aaeb55..ff9647ad 100644
--- a/src/lib/testing_api_cmd_check_keys.c
+++ b/src/lib/testing_api_cmd_check_keys.c
@@ -19,7 +19,14 @@
 
 /**
  * @file exchange-lib/testing_api_cmd_check_keys.c
- * @brief Implementation of "check keys" test command.
+ * @brief Implementation of "check keys" test command.  XXX-NOTE:
+ *        the number of 'expected keys' is NOT the number of the
+ *        downloaded keys, but rather the number of keys that the
+ *        libtalerutil library keeps locally.  As for the current
+ *        design, keys are _never_ discarded by the library,
+ *        therefore their (expected) number is monotonically
+ *        ascending.
+ *
  * @author Marcello Stanisci
  */
 
@@ -58,7 +65,7 @@ struct CheckKeysState
   /**
    * If GNUNET_YES, then the user must specify the
    * last_denom_issue_date manually.  This way, it is possible
-   * to force whatever X value here: /keys?last_denom_issue=X.
+   * to force whatever X value here (including 0): /keys?last_denom_issue=X.
    */
   unsigned int set_last_denom;
 
@@ -68,6 +75,18 @@ struct CheckKeysState
    * equals GNUNET_YES.
    */
   struct GNUNET_TIME_Absolute last_denom_date;
+
+  /**
+   * If GNUNET_YES, then we'll provide the "/keys" request.
+   * with the "now" argument.
+   */
+  int with_now;
+
+  /**
+   * Fake now as passed by the user.
+   */
+  struct GNUNET_TIME_Absolute now;
+
 };
 
 
@@ -105,7 +124,10 @@ check_keys_run (void *cls,
                                      cks->last_denom_date);  
     }
 
-    /* Means re-download /keys.  */
+    if (GNUNET_YES == cks->with_now)
+      TALER_EXCHANGE_set_now (is->exchange,
+                              cks->now);
+    /* Redownload /keys.  */
     GNUNET_break
       (0 == TALER_EXCHANGE_check_keys_current
         (is->exchange,
@@ -134,7 +156,7 @@ check_keys_run (void *cls,
     TALER_TESTING_interpreter_fail (is);
     return;
   }
-  /* /keys was updated, let's check they were OK! */
+  /* "/keys" was updated, let's check they were OK! */
   if (cks->num_denom_keys != is->keys->num_denom_keys)
   {
     /* Did not get the expected number of denomination keys! */
@@ -147,6 +169,9 @@ check_keys_run (void *cls,
     TALER_TESTING_interpreter_fail (is);
     return;
   }
+
+  /* Let's unset the fake now before moving on.  */
+  TALER_EXCHANGE_unset_now (is->exchange);
   TALER_TESTING_interpreter_next (is);
 }
 
@@ -252,6 +277,52 @@ TALER_TESTING_cmd_check_keys
 
 
 /**
+ * Make a "check keys" command.  This type of command
+ * checks whether the number of denomination keys from
+ * @a exchange matches @a num_denom_keys.
+ *
+ * @param label command label
+ * @param generation when this command is run, exactly @a
+ *        generation /keys downloads took place.  If the number
+ *        of downloads is less than @a generation, the logic will
+ *        first make sure that @a generation downloads are done,
+ *        and _then_ execute the rest of the command.
+ * @param num_denom_keys expected number of denomination keys.
+ * @param exchange connection handle to the exchange to test.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_keys_with_now
+  (const char *label,
+   unsigned int generation,
+   unsigned int num_denom_keys,
+   struct GNUNET_TIME_Absolute now)
+{
+  struct CheckKeysState *cks;
+
+  cks = GNUNET_new (struct CheckKeysState);
+  cks->generation = generation;
+  cks->num_denom_keys = num_denom_keys;
+  cks->now = now;
+  cks->with_now = GNUNET_YES;
+
+  /* Force to NOT cherry pick, otherwise they conflict.  */
+  cks->pull_all_keys = GNUNET_YES;
+
+  struct TALER_TESTING_Command cmd = {
+    .cls = cks,
+    .label = label,
+    .run = &check_keys_run,
+    .cleanup = &check_keys_cleanup
+  };
+
+  return cmd;
+}
+
+
+
+/**
  * Make a "check keys" command that forcedly does NOT cherry pick;
  * just redownload the whole /keys.  Then checks whether the number
  * of denomination keys from @a exchange matches @a num_denom_keys.
diff --git a/src/lib/testing_api_cmd_exec_keyup.c 
b/src/lib/testing_api_cmd_exec_keyup.c
index 576aab3c..e457a28e 100644
--- a/src/lib/testing_api_cmd_exec_keyup.c
+++ b/src/lib/testing_api_cmd_exec_keyup.c
@@ -46,6 +46,18 @@ struct KeyupState
    * Configuration file used by the command.
    */
   const char *config_filename;
+
+  /**
+   * If GNUNET_YES, then the fake @e now value will be
+   * passed to taler-exchange-keyup via the --time
+   * option.
+   */
+  unsigned int with_now;
+
+  /**
+   * User-provided fake now.
+   */
+  struct GNUNET_TIME_Absolute now;
 };
 
 
@@ -63,15 +75,30 @@ keyup_run (void *cls,
 {
   struct KeyupState *ks = cls;
 
-  ks->keyup_proc = GNUNET_OS_start_process
-    (GNUNET_NO,
-     GNUNET_OS_INHERIT_STD_ALL,
-     NULL, NULL, NULL,
-     "taler-exchange-keyup",
-     "taler-exchange-keyup",
-     "-c", ks->config_filename,
-     "-o", "auditor.in",
-     NULL);
+  if (GNUNET_YES == ks->with_now)
+  {
+     ks->keyup_proc = GNUNET_OS_start_process
+      (GNUNET_NO,
+       GNUNET_OS_INHERIT_STD_ALL,
+       NULL, NULL, NULL,
+       "taler-exchange-keyup",
+       "taler-exchange-keyup",
+       "-c", ks->config_filename,
+       "-o", "auditor.in",
+       "--time",
+       GNUNET_STRINGS_absolute_time_to_string (ks->now),
+       NULL);
+  }
+  else
+    ks->keyup_proc = GNUNET_OS_start_process
+      (GNUNET_NO,
+       GNUNET_OS_INHERIT_STD_ALL,
+       NULL, NULL, NULL,
+       "taler-exchange-keyup",
+       "taler-exchange-keyup",
+       "-c", ks->config_filename,
+       "-o", "auditor.in",
+       NULL);
 
   if (NULL == ks->keyup_proc)
   {
@@ -79,6 +106,9 @@ keyup_run (void *cls,
     TALER_TESTING_interpreter_fail (is);
     return;
   }
+
+  /* This function does not tell whether the command
+   * succeeded or not!  */
   TALER_TESTING_wait_for_sigchld (is);
 }
 
@@ -139,6 +169,39 @@ keyup_traits (void *cls,
 
 
 /**
+ * Make the "keyup" CMD, with "--timestamp" option.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ * @param now Unix timestamp representing the fake "now".
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_keyup_with_now
+  (const char *label,
+   const char *config_filename,
+   struct GNUNET_TIME_Absolute now)
+{
+  struct KeyupState *ks;
+
+  ks = GNUNET_new (struct KeyupState);
+  ks->config_filename = config_filename;
+  ks->now = now;
+  ks->with_now = GNUNET_YES;
+
+  struct TALER_TESTING_Command cmd = {
+    .cls = ks,
+    .label = label,
+    .run = &keyup_run,
+    .cleanup = &keyup_cleanup,
+    .traits = &keyup_traits
+  };
+
+  return cmd;
+}
+
+/**
  * Make the "keyup" CMD.
  *
  * @param label command label.
diff --git a/src/lib/testing_api_cmd_fakebank_transfer.c 
b/src/lib/testing_api_cmd_fakebank_transfer.c
index 43f72573..cff16157 100644
--- a/src/lib/testing_api_cmd_fakebank_transfer.c
+++ b/src/lib/testing_api_cmd_fakebank_transfer.c
@@ -102,6 +102,11 @@ struct FakebankTransferState
   uint64_t serial_id;
 
   /**
+   * Timestamp of the transaction (as returned from the bank).
+   */
+  struct GNUNET_TIME_Absolute timestamp;
+
+  /**
    * Exchange URL.  This value is fed to the bank when requesting
    * the wire transfer; note: the bank needs it because a merchant
    * might want to know which exchange performed a wire transfer to
@@ -182,21 +187,22 @@ do_retry (void *cls)
  *        bogus (fails to follow the protocol)
  * @param ec taler-specific error code, #TALER_EC_NONE on success
  * @param serial_id unique ID of the wire transfer
+ * @param timestamp time stamp of the transaction made.
  * @param full_response full response from the exchange (for
  *        logging, in case of errors)
  */
 static void
 add_incoming_cb (void *cls,
                  unsigned int http_status,
-                enum TALER_ErrorCode ec,
+                 enum TALER_ErrorCode ec,
                  uint64_t serial_id,
+                 struct GNUNET_TIME_Absolute timestamp,
                  const json_t *full_response)
 {
   struct FakebankTransferState *fts = cls;
   struct TALER_TESTING_Interpreter *is = fts->is;
 
   fts->aih = NULL;
-  fts->serial_id = serial_id;
   if (MHD_HTTP_OK != http_status)
   {
     if (GNUNET_YES == fts->do_retry)
@@ -205,18 +211,20 @@ add_incoming_cb (void *cls,
            (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
           (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                    "Retrying fakebank transfer failed with %u/%d\n",
-                    http_status,
-                    (int) ec);
+        GNUNET_log
+          (GNUNET_ERROR_TYPE_INFO,
+           "Retrying fakebank transfer failed with %u/%d\n",
+           http_status,
+           (int) ec);
        /* on DB conflicts, do not use backoff */
        if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
          fts->backoff = GNUNET_TIME_UNIT_ZERO;
        else
          fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
-       fts->retry_task = GNUNET_SCHEDULER_add_delayed (fts->backoff,
-                                                        &do_retry,
-                                                        fts);
+       fts->retry_task = GNUNET_SCHEDULER_add_delayed
+          (fts->backoff,
+           &do_retry,
+           fts);
        return;
       }
     }
@@ -228,6 +236,9 @@ add_incoming_cb (void *cls,
     TALER_TESTING_interpreter_fail (is);
     return;
   }
+
+  fts->serial_id = serial_id;
+  fts->timestamp = timestamp;
   TALER_TESTING_interpreter_next (is);
 }
 
@@ -422,7 +433,7 @@ fakebank_transfer_traits (void *cls,
                           unsigned int index)
 {
   struct FakebankTransferState *fts = cls;
-  #define MANDATORY 6
+  #define MANDATORY 7
   struct TALER_TESTING_Trait traits[MANDATORY + 1] = {
     TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT
       (&fts->debit_account_no),
@@ -431,6 +442,7 @@ fakebank_transfer_traits (void *cls,
     TALER_TESTING_make_trait_url (0, fts->exchange_url),
     TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id),
     TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
+    TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp)
   };
 
   /**
@@ -444,7 +456,7 @@ fakebank_transfer_traits (void *cls,
   else
     traits[MANDATORY - 1] = TALER_TESTING_make_trait_reserve_priv
       (0, &fts->reserve_priv),
-  
+
   traits[MANDATORY] = TALER_TESTING_trait_end ();
 
   return TALER_TESTING_get_trait (traits,
diff --git a/src/lib/testing_api_cmd_payback.c 
b/src/lib/testing_api_cmd_payback.c
index dd8652ae..9b49108c 100644
--- a/src/lib/testing_api_cmd_payback.c
+++ b/src/lib/testing_api_cmd_payback.c
@@ -188,8 +188,7 @@ payback_cb (void *cls,
       TALER_TESTING_interpreter_fail (is);
       return;
     }
-    if (0 != memcmp (reserve_pub, &rp,
-                     sizeof (struct TALER_ReservePublicKeyP)))
+    if (0 != GNUNET_memcmp (reserve_pub, &rp))
     {
       GNUNET_break (0);
       TALER_TESTING_interpreter_fail (is);
diff --git a/src/lib/testing_api_cmd_refresh.c 
b/src/lib/testing_api_cmd_refresh.c
index 767c5296..ec885581 100644
--- a/src/lib/testing_api_cmd_refresh.c
+++ b/src/lib/testing_api_cmd_refresh.c
@@ -506,7 +506,7 @@ do_link_retry (void *cls)
 static void
 link_cb (void *cls,
          unsigned int http_status,
-        enum TALER_ErrorCode ec,
+         enum TALER_ErrorCode ec,
          unsigned int num_coins,
          const struct TALER_CoinSpendPrivateKeyP *coin_privs,
          const struct TALER_DenominationSignature *sigs,
@@ -591,10 +591,9 @@ link_cb (void *cls,
     /* check that the coins match */
     for (unsigned int i=0;i<num_coins;i++)
       for (unsigned int j=i+1;j<num_coins;j++)
-       if (0 == memcmp
-          (&coin_privs[i], &coin_privs[j],
-           sizeof (struct TALER_CoinSpendPrivateKeyP)))
-         GNUNET_break (0);
+        if (0 == GNUNET_memcmp
+            (&coin_privs[i], &coin_privs[j]))
+          GNUNET_break (0);
     /* Note: coins might be legitimately permutated in here... */
     found = 0;
 
@@ -612,9 +611,8 @@ link_cb (void *cls,
     for (unsigned int i=0;i<num_coins;i++)
       for (unsigned int j=0;j<num_coins;j++)
       {
-       if ( (0 == memcmp
-                (&coin_privs[i], &fc[j].coin_priv,
-                sizeof (struct TALER_CoinSpendPrivateKeyP))) &&
+       if ( (0 == GNUNET_memcmp
+          (&coin_privs[i], &fc[j].coin_priv)) &&
             (0 == GNUNET_CRYPTO_rsa_signature_cmp
                 (fc[i].sig.rsa_signature,
                  sigs[j].rsa_signature)) &&
diff --git a/src/lib/testing_api_cmd_sleep.c b/src/lib/testing_api_cmd_sleep.c
index 165d0aae..188671be 100644
--- a/src/lib/testing_api_cmd_sleep.c
+++ b/src/lib/testing_api_cmd_sleep.c
@@ -40,6 +40,25 @@ struct SleepState
   unsigned int duration;
 };
 
+/**
+ * No traits to offer, just provide a stub to be called when
+ * some CMDs iterates through the list of all the commands.
+ *
+ * @param cls closure.
+ * @param ret[out] result.
+ * @param trait name of the trait.
+ * @param index index number of the trait to return.
+ *
+ * @return #GNUNET_OK on success.
+ */
+static int
+sleep_traits (void *cls,
+              const void **ret,
+              const char *trait,
+              unsigned int index)
+{
+  return GNUNET_NO;
+}
 
 /**
  * Run the command.
@@ -97,8 +116,106 @@ TALER_TESTING_cmd_sleep (const char *label,
     .cls = ss,
     .label = label,
     .run = &sleep_run,
-    .cleanup = &sleep_cleanup
+    .cleanup = &sleep_cleanup,
+    .traits = &sleep_traits
   };
 
   return cmd;
 }
+
+/**
+ * Cleanup the state from a "wait service" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+wait_service_cleanup (void *cls,
+                      const struct TALER_TESTING_Command *cmd)
+{
+  /* nothing to clean.  */
+  return;
+}
+
+/**
+ * No traits to offer, just provide a stub to be called when
+ * some CMDs iterates through the list of all the commands.
+ *
+ * @param cls closure.
+ * @param ret[out] result.
+ * @param trait name of the trait.
+ * @param index index number of the trait to return.
+ *
+ * @return #GNUNET_OK on success.
+ */
+static int
+wait_service_traits (void *cls,
+                     const void **ret,
+                     const char *trait,
+                     unsigned int index)
+{
+  return GNUNET_NO;
+}
+
+/**
+ * Run a "wait service" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command being run.
+ * @param is the interpreter state.
+ */
+static void
+wait_service_run (void *cls,
+                  const struct TALER_TESTING_Command *cmd,
+                  struct TALER_TESTING_Interpreter *is)
+{
+  unsigned int iter = 0;
+  const char *url = cmd->cls;
+  char *wget_cmd;
+
+  GNUNET_asprintf (&wget_cmd,
+                   "wget -q -t 1 -T 1 %s\n",
+                   url);
+  do
+  {
+    fprintf (stderr, ".");
+
+    if (10 == iter++)
+    {
+      TALER_LOG_ERROR ("Could not reach the proxied service\n");
+      TALER_TESTING_interpreter_fail (is); 
+      GNUNET_free (wget_cmd);
+      return; 
+    }
+  }
+  while (0 != system (wget_cmd));
+  
+  GNUNET_free (wget_cmd);
+  TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * This CMD simply tries to connect via HTTP to the
+ * service addressed by @a url.  It attemps 10 times
+ * before giving up and make the test fail.
+ *
+ * @param label label for the command.
+ * @param url complete URL to connect to.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wait_service (const char *label,
+                                const char *url)
+{
+  struct TALER_TESTING_Command cmd = {
+    .label = label,
+    .run = wait_service_run,
+    .cleanup = wait_service_cleanup,
+    .traits = wait_service_traits,
+    .cls = (void *) url
+  };
+  
+  return cmd;
+}
+
+/* end of testing_api_cmd_sleep.c  */
diff --git a/src/lib/testing_api_cmd_track.c b/src/lib/testing_api_cmd_track.c
index 4898a097..6afb0ac6 100644
--- a/src/lib/testing_api_cmd_track.c
+++ b/src/lib/testing_api_cmd_track.c
@@ -613,9 +613,8 @@ track_transfer_cb
          TALER_JSON_merchant_wire_signature_hash (wire_details,
                                                   &h_wire_details));
 
-      if (0 != memcmp (&h_wire_details,
-                       h_wire,
-                       sizeof (struct GNUNET_HashCode)))
+      if (0 != GNUNET_memcmp (&h_wire_details,
+                              h_wire))
       {
         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                     "Wire hash missmath to command %s\n",
diff --git a/src/lib/testing_api_loop.c b/src/lib/testing_api_loop.c
index 39a9b71a..071388f2 100644
--- a/src/lib/testing_api_loop.c
+++ b/src/lib/testing_api_loop.c
@@ -620,7 +620,6 @@ TALER_TESTING_cert_cb
         (GNUNET_ERROR_TYPE_ERROR,
          "Got NULL response for /keys"
          " during execution!\n");
-
   }
   else
   {
diff --git a/src/lib/testing_api_trait_wtid.c b/src/lib/testing_api_trait_time.c
similarity index 64%
copy from src/lib/testing_api_trait_wtid.c
copy to src/lib/testing_api_trait_time.c
index 67232971..384ff807 100644
--- a/src/lib/testing_api_trait_wtid.c
+++ b/src/lib/testing_api_trait_time.c
@@ -18,8 +18,8 @@
 */
 
 /**
- * @file exchange-lib/testing_api_trait_number.c
- * @brief traits to offer numbers
+ * @file exchange-lib/testing_api_trait_time.c
+ * @brief traits to offer time stamps.
  * @author Marcello Stanisci
  */
 #include "platform.h"
@@ -29,48 +29,47 @@
 #include "taler_signatures.h"
 #include "taler_testing_lib.h"
 
-#define TALER_TESTING_TRAIT_WTID "wtid"
+#define TALER_TESTING_TRAIT_TIME_ABS "time-abs"
 
 /**
- * Obtain a WTID value from @a cmd.
+ * Obtain a absolute time from @a cmd.
  *
  * @param cmd command to extract trait from
- * @param index which WTID to pick if @a cmd has multiple on
- *        offer
- * @param wtid[out] set to the wanted WTID.
+ * @param index which time stamp to pick if
+ *        @a cmd has multiple on offer.
+ * @param time[out] set to the wanted WTID.
  * @return #GNUNET_OK on success
  */
 int
-TALER_TESTING_get_trait_wtid
+TALER_TESTING_get_trait_absolute_time
   (const struct TALER_TESTING_Command *cmd,
    unsigned int index,
-   const struct TALER_WireTransferIdentifierRawP **wtid)
+   const struct GNUNET_TIME_Absolute **time)
 {
   return cmd->traits (cmd->cls,
-                      (const void **) wtid,
-                      TALER_TESTING_TRAIT_WTID,
+                      (const void **) time,
+                      TALER_TESTING_TRAIT_TIME_ABS,
                       index);
 }
 
-
 /**
- * Offer a WTID.
+ * Offer a absolute time.
  *
  * @param index associate the object with this index
- * @param wtid which object should be returned
+ * @param time which object should be returned
  * @return the trait.
  */
 struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_wtid
+TALER_TESTING_make_trait_absolute_time
   (unsigned int index,
-   const struct TALER_WireTransferIdentifierRawP *wtid)
+   const struct GNUNET_TIME_Absolute *time)
 {
   struct TALER_TESTING_Trait ret = {
     .index = index,
-    .trait_name = TALER_TESTING_TRAIT_WTID,
-    .ptr = (const void *) wtid
+    .trait_name = TALER_TESTING_TRAIT_TIME_ABS,
+    .ptr = (const void *) time
   };
   return ret;
 }
 
-/* end of testing_api_trait_number.c */
+/* end of testing_api_trait_time.c */
diff --git a/src/util/crypto.c b/src/util/crypto.c
index b44c31ff..95eb11eb 100644
--- a/src/util/crypto.c
+++ b/src/util/crypto.c
@@ -77,22 +77,33 @@ TALER_gcrypt_init ()
  * is not expired, and the signature is correct.
  *
  * @param coin_public_info the coin public info to check for validity
+ * @param denom_pub denomination key, must match @a coin_public_info's 
`denom_pub_hash`
  * @return #GNUNET_YES if the coin is valid,
  *         #GNUNET_NO if it is invalid
  *         #GNUNET_SYSERR if an internal error occured
  */
 int
-TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info)
+TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info,
+                       const struct TALER_DenominationPublicKey *denom_pub)
 {
   struct GNUNET_HashCode c_hash;
-
+#if 1 /* sanity check of invariant, could probably be disabled in production
+         for slightly more performance */
+  struct GNUNET_HashCode d_hash;
+
+  GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
+                                     &d_hash);
+  GNUNET_assert (0 ==
+                 GNUNET_memcmp (&d_hash,
+                                &coin_public_info->denom_pub_hash));
+#endif
   GNUNET_CRYPTO_hash (&coin_public_info->coin_pub,
                       sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
                       &c_hash);
   if (GNUNET_OK !=
       GNUNET_CRYPTO_rsa_verify (&c_hash,
                                 coin_public_info->denom_sig.rsa_signature,
-                                coin_public_info->denom_pub.rsa_public_key))
+                                denom_pub->rsa_public_key))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "coin signature is invalid\n");
diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c
index 4713b3a3..bba9275a 100644
--- a/src/util/test_crypto.c
+++ b/src/util/test_crypto.c
@@ -60,16 +60,14 @@ test_high_level ()
                                      &coin_pub,
                                      &secret2);
   GNUNET_assert (0 ==
-                memcmp (&secret,
-                        &secret2,
-                        sizeof (secret)));
+                 GNUNET_memcmp (&secret,
+                                &secret2));
   TALER_link_recover_transfer_secret (&trans_pub,
                                       &coin_priv,
                                       &secret2);
   GNUNET_assert (0 ==
-                memcmp (&secret,
-                        &secret2,
-                        sizeof (secret)));
+                 GNUNET_memcmp (&secret,
+                                &secret2));
   TALER_planchet_setup_refresh (&secret,
                                 0,
                                 &fc1);
@@ -77,9 +75,8 @@ test_high_level ()
                                 1,
                                 &fc2);
   GNUNET_assert (0 !=
-                 memcmp (&fc1,
-                         &fc2,
-                         sizeof (struct TALER_PlanchetSecretsP)));
+                 GNUNET_memcmp (&fc1,
+                                &fc2));
   return 0;
 }
 
diff --git a/src/wire-plugins/plugin_wire_taler-bank.c 
b/src/wire-plugins/plugin_wire_taler-bank.c
index 096e81df..724ad2a4 100644
--- a/src/wire-plugins/plugin_wire_taler-bank.c
+++ b/src/wire-plugins/plugin_wire_taler-bank.c
@@ -619,6 +619,7 @@ taler_bank_prepare_wire_transfer (void *cls,
  *                    0 if the bank's reply is bogus (fails to follow the 
protocol)
  * @param ec error code from the bank
  * @param serial_id unique ID of the wire transfer in the bank's records; 
UINT64_MAX on error
+ * @param timestamp time when the transfer was settled by the bank.
  * @param json detailed response from the HTTPD, or NULL if reply was not JSON
  */
 static void
@@ -626,6 +627,7 @@ execute_cb (void *cls,
             unsigned int http_status,
             enum TALER_ErrorCode ec,
             uint64_t serial_id,
+            struct GNUNET_TIME_Absolute timestamp,
             const json_t *json)
 {
   struct TALER_WIRE_ExecuteHandle *eh = cls;
@@ -806,7 +808,7 @@ taler_bank_execute_wire_transfer (void *cls,
                                             wire_s,
                                             &amount,
                                             (uint64_t) origin_account.no,
-                                           (uint64_t) destination_account.no,
+                                            (uint64_t) destination_account.no,
                                             &execute_cb,
                                             eh);
   GNUNET_free_non_null (origin_account.bank_base_url);
@@ -1012,10 +1014,11 @@ bhist_cb (void *cls,
  * transfers.  The @a start_off value must thus match the value of
  * a `row_off` argument previously given to the @a hres_cb.  Use
  * NULL to query transfers from the beginning of time (with
- * positive @a num_results) or from the lataler_bank committed transfers
- * (with negative @a num_results).
+ * positive @a num_results) or from the lataler_bank committed
+ * transfers (with negative @a num_results).
  *
- * @param cls the @e cls of this struct with the plugin-specific state
+ * @param cls the @e cls of this struct with the plugin-specific
+ *        state
  * @param account_section specifies the configuration section which
  *        identifies the account for which we should get the history
  * @param direction what kinds of wire transfers should be returned
@@ -1057,13 +1060,18 @@ taler_bank_get_history (void *cls,
        (sizeof (uint64_t) != start_off_len) )
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Wire plugin 'taler_bank' got start offset of wrong size (%llu 
instead of %llu)\n",
+                "Wire plugin 'taler_bank' got"
+                " start offset of wrong size (%llu"
+                " instead of %llu)\n",
                 (unsigned long long) start_off_len,
                 (unsigned long long) sizeof (uint64_t));
     GNUNET_break (0);
-    /* Probably something is wrong with the DB, some other component
-     * wrote a wrong value to it.  Instead of completely stopping to work,
-     * we just scan from the beginning. */
+
+    /**
+     * Probably something is wrong with the DB, some
+     * other component wrote a wrong value to it.  Instead
+     * of completely stopping to work, we just scan from the
+     * beginning. */
     start_off = NULL;
   }
   if (NULL == start_off)
@@ -1107,7 +1115,7 @@ taler_bank_get_history (void *cls,
                                 &whh->auth,
                                 (uint64_t) account.no,
                                 direction,
-                                /* Defaults to descending ordering always. */
+               /* Defaults to descending ordering always. */
                                 GNUNET_NO,
                                 start_row,
                                 num_results,
@@ -1129,6 +1137,99 @@ taler_bank_get_history (void *cls,
 }
 
 
+
+/**
+ * Query transfer history of an account.  The query is based on
+ * the dates where the wire transfers got settled at the bank.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific
+ *        state
+ * @param account_section specifies the configuration section which
+ *        identifies the account for which we should get the
+ *        history
+ * @param direction what kinds of wire transfers should be returned
+ * @param start_date each history entry in the result will be time
+ *        stamped after, or at this date.
+ * @param end_date each history entry in the result will be time
+ *        stamped before, or at this date.
+ * @param hres_cb the callback to call with the transaction history
+ * @param hres_cb_cls closure for the above callback
+ * @param return the operation handle, or NULL on errors.
+ */
+static struct TALER_WIRE_HistoryHandle *
+taler_bank_get_history_range
+  (void *cls,
+   const char *account_section,
+   enum TALER_BANK_Direction direction,
+   struct GNUNET_TIME_Absolute start_date,
+   struct GNUNET_TIME_Absolute end_date,
+   TALER_WIRE_HistoryResultCallback hres_cb,
+   void *hres_cb_cls)
+{
+  GNUNET_break (0);
+  return NULL;
+
+  struct Account account;
+  struct TalerBankClosure *tc = cls;
+  struct TALER_WIRE_HistoryHandle *whh;
+
+  if (GNUNET_OK !=
+      parse_account_cfg (tc->cfg,
+                         account_section,
+                         &account))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Could not parse the config section '%s'\n",
+                account_section);
+    return NULL;
+  }
+
+  whh = GNUNET_new (struct TALER_WIRE_HistoryHandle);
+  whh->hres_cb = hres_cb;
+  whh->hres_cb_cls = hres_cb_cls;
+
+  if (GNUNET_OK !=
+      TALER_BANK_auth_parse_cfg (tc->cfg,
+                                 account_section,
+                                 &whh->auth))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Could not parse the auth values from '%s'\n",
+                account_section);
+    GNUNET_free (whh);
+    return NULL;
+  }
+
+
+  whh->hh = TALER_BANK_history_range (tc->ctx,
+                                      account.bank_base_url,
+                                      &whh->auth,
+                                      account.no,
+                                      direction,
+                            /* Just always descending.  */
+                                      GNUNET_NO,
+                                      start_date,
+                                      end_date,
+                                      &bhist_cb,
+                                      whh);
+  if (NULL == whh->hh)
+  {
+    GNUNET_break (0);
+    taler_bank_get_history_cancel (NULL,
+                                   whh);
+    GNUNET_free (account.hostname);
+    GNUNET_free (account.bank_base_url);
+    return NULL;
+  }
+
+  GNUNET_free (account.hostname);
+  GNUNET_free (account.bank_base_url);
+  GNUNET_assert (NULL != whh);
+
+  return whh;
+}
+
+
 /**
  * Context for a rejection operation.
  */
@@ -1331,6 +1432,7 @@ libtaler_plugin_wire_taler_bank_init (void *cls)
   plugin->execute_wire_transfer = &taler_bank_execute_wire_transfer;
   plugin->execute_wire_transfer_cancel = 
&taler_bank_execute_wire_transfer_cancel;
   plugin->get_history = &taler_bank_get_history;
+  plugin->get_history_range = &taler_bank_get_history_range;
   plugin->get_history_cancel = &taler_bank_get_history_cancel;
   plugin->reject_transfer = &taler_bank_reject_transfer;
   plugin->reject_transfer_cancel = &taler_bank_reject_transfer_cancel;
diff --git a/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c 
b/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c
index da1d43c1..4c2af52c 100644
--- a/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c
+++ b/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c
@@ -207,9 +207,8 @@ history_result_cb
     GNUNET_SCHEDULER_shutdown ();
     return GNUNET_SYSERR;
   }
-  if (0 != memcmp (&wtid,
-                   &details->wtid,
-                   sizeof (struct TALER_WireTransferIdentifierRawP)))
+  if (0 != GNUNET_memcmp (&wtid,
+                          &details->wtid))
   {
     GNUNET_break (0);
     global_ret = GNUNET_SYSERR;

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]