aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-05-07 20:22:02 +0200
committerChristian Grothoff <christian@grothoff.org>2020-05-07 20:22:02 +0200
commit7ab9d526f23d52d87d47aa195351022db3748d2c (patch)
tree2e0f9e4a077098a0babebb2b79530c189cbc8278
parentaf52541eacf5305977701fa24a530797994feb19 (diff)
downloadexchange-7ab9d526f23d52d87d47aa195351022db3748d2c.tar.gz
exchange-7ab9d526f23d52d87d47aa195351022db3748d2c.zip
towards changing timestamp in deposit confirmation (tests failing)
-rw-r--r--src/auditor/taler-auditor-httpd_deposit-confirmation.c5
-rw-r--r--src/auditor/taler-helper-auditor-coins.c8
-rw-r--r--src/auditor/taler-helper-auditor-deposits.c9
-rw-r--r--src/auditordb/auditor-0001.sql2
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c10
-rw-r--r--src/exchange/taler-exchange-aggregator.c12
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c173
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c2
-rw-r--r--src/exchangedb/exchange-0001.sql3
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c62
-rw-r--r--src/exchangedb/test_exchangedb.c71
-rw-r--r--src/include/taler_auditordb_plugin.h4
-rw-r--r--src/include/taler_error_codes.h45
-rw-r--r--src/include/taler_exchange_service.h2
-rw-r--r--src/include/taler_exchangedb_plugin.h18
-rw-r--r--src/include/taler_signatures.h7
-rw-r--r--src/include/taler_testing_lib.h18
-rw-r--r--src/lib/auditor_api_deposit_confirmation.c17
-rw-r--r--src/lib/exchange_api_common.c2
-rw-r--r--src/lib/exchange_api_deposit.c9
-rw-r--r--src/lib/exchange_api_refund.c7
-rw-r--r--src/testing/test_taler_exchange_aggregator.c24
-rw-r--r--src/testing/testing_api_cmd_auditor_deposit_confirmation.c8
-rw-r--r--src/testing/testing_api_cmd_deposit.c35
-rw-r--r--src/testing/testing_api_cmd_insert_deposit.c26
25 files changed, 390 insertions, 189 deletions
diff --git a/src/auditor/taler-auditor-httpd_deposit-confirmation.c b/src/auditor/taler-auditor-httpd_deposit-confirmation.c
index 5f84a7253..1039164c4 100644
--- a/src/auditor/taler-auditor-httpd_deposit-confirmation.c
+++ b/src/auditor/taler-auditor-httpd_deposit-confirmation.c
@@ -155,7 +155,7 @@ verify_and_execute_deposit_confirmation (
155 .purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)), 155 .purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)),
156 .h_contract_terms = dc->h_contract_terms, 156 .h_contract_terms = dc->h_contract_terms,
157 .h_wire = dc->h_wire, 157 .h_wire = dc->h_wire,
158 .timestamp = GNUNET_TIME_absolute_hton (dc->timestamp), 158 .exchange_timestamp = GNUNET_TIME_absolute_hton (dc->exchange_timestamp),
159 .refund_deadline = GNUNET_TIME_absolute_hton (dc->refund_deadline), 159 .refund_deadline = GNUNET_TIME_absolute_hton (dc->refund_deadline),
160 .coin_pub = dc->coin_pub, 160 .coin_pub = dc->coin_pub,
161 .merchant = dc->merchant 161 .merchant = dc->merchant
@@ -224,7 +224,8 @@ TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh,
224 struct GNUNET_JSON_Specification spec[] = { 224 struct GNUNET_JSON_Specification spec[] = {
225 GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &dc.h_contract_terms), 225 GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &dc.h_contract_terms),
226 GNUNET_JSON_spec_fixed_auto ("h_wire", &dc.h_wire), 226 GNUNET_JSON_spec_fixed_auto ("h_wire", &dc.h_wire),
227 GNUNET_JSON_spec_absolute_time ("timestamp", &dc.timestamp), 227 GNUNET_JSON_spec_absolute_time ("exchange_timestamp",
228 &dc.exchange_timestamp),
228 GNUNET_JSON_spec_absolute_time ("refund_deadline", &dc.refund_deadline), 229 GNUNET_JSON_spec_absolute_time ("refund_deadline", &dc.refund_deadline),
229 TALER_JSON_spec_amount ("amount_without_fee", &dc.amount_without_fee), 230 TALER_JSON_spec_amount ("amount_without_fee", &dc.amount_without_fee),
230 GNUNET_JSON_spec_fixed_auto ("coin_pub", &dc.coin_pub), 231 GNUNET_JSON_spec_fixed_auto ("coin_pub", &dc.coin_pub),
diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c
index 2e32c5698..158baa8b3 100644
--- a/src/auditor/taler-helper-auditor-coins.c
+++ b/src/auditor/taler-helper-auditor-coins.c
@@ -1535,7 +1535,8 @@ refresh_session_cb (void *cls,
1535 * 1535 *
1536 * @param cls closure 1536 * @param cls closure
1537 * @param rowid unique serial ID for the deposit in our DB 1537 * @param rowid unique serial ID for the deposit in our DB
1538 * @param timestamp when did the deposit happen 1538 * @param exchange_timestamp when did the exchange get the deposit
1539 * @param wallet_timestamp when did the contract signing happen
1539 * @param merchant_pub public key of the merchant 1540 * @param merchant_pub public key of the merchant
1540 * @param denom_pub denomination public key of @a coin_pub 1541 * @param denom_pub denomination public key of @a coin_pub
1541 * @param coin_pub public key of the coin 1542 * @param coin_pub public key of the coin
@@ -1553,7 +1554,8 @@ refresh_session_cb (void *cls,
1553static int 1554static int
1554deposit_cb (void *cls, 1555deposit_cb (void *cls,
1555 uint64_t rowid, 1556 uint64_t rowid,
1556 struct GNUNET_TIME_Absolute timestamp, 1557 struct GNUNET_TIME_Absolute exchange_timestamp,
1558 struct GNUNET_TIME_Absolute wallet_timestamp,
1557 const struct TALER_MerchantPublicKeyP *merchant_pub, 1559 const struct TALER_MerchantPublicKeyP *merchant_pub,
1558 const struct TALER_DenominationPublicKey *denom_pub, 1560 const struct TALER_DenominationPublicKey *denom_pub,
1559 const struct TALER_CoinSpendPublicKeyP *coin_pub, 1561 const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -1611,7 +1613,7 @@ deposit_cb (void *cls,
1611 .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT), 1613 .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT),
1612 .purpose.size = htonl (sizeof (dr)), 1614 .purpose.size = htonl (sizeof (dr)),
1613 .h_contract_terms = *h_contract_terms, 1615 .h_contract_terms = *h_contract_terms,
1614 .timestamp = GNUNET_TIME_absolute_hton (timestamp), 1616 .wallet_timestamp = GNUNET_TIME_absolute_hton (wallet_timestamp),
1615 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline), 1617 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
1616 .deposit_fee = issue->fee_deposit, 1618 .deposit_fee = issue->fee_deposit,
1617 .merchant = *merchant_pub, 1619 .merchant = *merchant_pub,
diff --git a/src/auditor/taler-helper-auditor-deposits.c b/src/auditor/taler-helper-auditor-deposits.c
index 291558590..ed23c6a52 100644
--- a/src/auditor/taler-helper-auditor-deposits.c
+++ b/src/auditor/taler-helper-auditor-deposits.c
@@ -114,11 +114,15 @@ test_dc (void *cls,
114 .h_wire = dc->h_wire, 114 .h_wire = dc->h_wire,
115 .refund_deadline = dc->refund_deadline 115 .refund_deadline = dc->refund_deadline
116 }; 116 };
117 struct GNUNET_TIME_Absolute exchange_timestamp;
118 struct TALER_Amount deposit_fee;
117 119
118 qs = TALER_ARL_edb->have_deposit (TALER_ARL_edb->cls, 120 qs = TALER_ARL_edb->have_deposit (TALER_ARL_edb->cls,
119 TALER_ARL_esession, 121 TALER_ARL_esession,
120 &dep, 122 &dep,
121 GNUNET_NO /* do not check refund deadline */); 123 GNUNET_NO /* do not check refund deadline */,
124 &deposit_fee,
125 &exchange_timestamp);
122 if (qs > 0) 126 if (qs > 0)
123 { 127 {
124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -137,7 +141,8 @@ test_dc (void *cls,
137 TALER_ARL_report (report_deposit_confirmation_inconsistencies, 141 TALER_ARL_report (report_deposit_confirmation_inconsistencies,
138 json_pack ("{s:o, s:o, s:I, s:o}", 142 json_pack ("{s:o, s:o, s:I, s:o}",
139 "timestamp", 143 "timestamp",
140 TALER_ARL_json_from_time_abs (dc->timestamp), 144 TALER_ARL_json_from_time_abs (
145 dc->exchange_timestamp),
141 "amount", 146 "amount",
142 TALER_JSON_from_amount (&dc->amount_without_fee), 147 TALER_JSON_from_amount (&dc->amount_without_fee),
143 "rowid", 148 "rowid",
diff --git a/src/auditordb/auditor-0001.sql b/src/auditordb/auditor-0001.sql
index ff8867bee..b511a4d5b 100644
--- a/src/auditordb/auditor-0001.sql
+++ b/src/auditordb/auditor-0001.sql
@@ -251,7 +251,7 @@ CREATE TABLE IF NOT EXISTS deposit_confirmations
251 ,serial_id BIGSERIAL UNIQUE 251 ,serial_id BIGSERIAL UNIQUE
252 ,h_contract_terms BYTEA CHECK (LENGTH(h_contract_terms)=64) 252 ,h_contract_terms BYTEA CHECK (LENGTH(h_contract_terms)=64)
253 ,h_wire BYTEA CHECK (LENGTH(h_wire)=64) 253 ,h_wire BYTEA CHECK (LENGTH(h_wire)=64)
254 ,timestamp INT8 NOT NULL 254 ,exchange_timestamp INT8 NOT NULL
255 ,refund_deadline INT8 NOT NULL 255 ,refund_deadline INT8 NOT NULL
256 ,amount_without_fee_val INT8 NOT NULL 256 ,amount_without_fee_val INT8 NOT NULL
257 ,amount_without_fee_frac INT4 NOT NULL 257 ,amount_without_fee_frac INT4 NOT NULL
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c
index 467c4c6db..4f9101fdc 100644
--- a/src/auditordb/plugin_auditordb_postgres.c
+++ b/src/auditordb/plugin_auditordb_postgres.c
@@ -269,7 +269,7 @@ postgres_get_session (void *cls)
269 "(master_pub" 269 "(master_pub"
270 ",h_contract_terms" 270 ",h_contract_terms"
271 ",h_wire" 271 ",h_wire"
272 ",timestamp" 272 ",exchange_timestamp"
273 ",refund_deadline" 273 ",refund_deadline"
274 ",amount_without_fee_val" 274 ",amount_without_fee_val"
275 ",amount_without_fee_frac" 275 ",amount_without_fee_frac"
@@ -286,7 +286,7 @@ postgres_get_session (void *cls)
286 " serial_id" 286 " serial_id"
287 ",h_contract_terms" 287 ",h_contract_terms"
288 ",h_wire" 288 ",h_wire"
289 ",timestamp" 289 ",exchange_timestamp"
290 ",refund_deadline" 290 ",refund_deadline"
291 ",amount_without_fee_val" 291 ",amount_without_fee_val"
292 ",amount_without_fee_frac" 292 ",amount_without_fee_frac"
@@ -1126,7 +1126,7 @@ postgres_insert_deposit_confirmation (
1126 GNUNET_PQ_query_param_auto_from_type (&dc->master_public_key), 1126 GNUNET_PQ_query_param_auto_from_type (&dc->master_public_key),
1127 GNUNET_PQ_query_param_auto_from_type (&dc->h_contract_terms), 1127 GNUNET_PQ_query_param_auto_from_type (&dc->h_contract_terms),
1128 GNUNET_PQ_query_param_auto_from_type (&dc->h_wire), 1128 GNUNET_PQ_query_param_auto_from_type (&dc->h_wire),
1129 TALER_PQ_query_param_absolute_time (&dc->timestamp), 1129 TALER_PQ_query_param_absolute_time (&dc->exchange_timestamp),
1130 TALER_PQ_query_param_absolute_time (&dc->refund_deadline), 1130 TALER_PQ_query_param_absolute_time (&dc->refund_deadline),
1131 TALER_PQ_query_param_amount (&dc->amount_without_fee), 1131 TALER_PQ_query_param_amount (&dc->amount_without_fee),
1132 GNUNET_PQ_query_param_auto_from_type (&dc->coin_pub), 1132 GNUNET_PQ_query_param_auto_from_type (&dc->coin_pub),
@@ -1207,8 +1207,8 @@ deposit_confirmation_cb (void *cls,
1207 &dc.h_contract_terms), 1207 &dc.h_contract_terms),
1208 GNUNET_PQ_result_spec_auto_from_type ("h_wire", 1208 GNUNET_PQ_result_spec_auto_from_type ("h_wire",
1209 &dc.h_wire), 1209 &dc.h_wire),
1210 GNUNET_PQ_result_spec_absolute_time ("timestamp", 1210 GNUNET_PQ_result_spec_absolute_time ("exchange_timestamp",
1211 &dc.timestamp), 1211 &dc.exchange_timestamp),
1212 GNUNET_PQ_result_spec_absolute_time ("refund_deadline", 1212 GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
1213 &dc.refund_deadline), 1213 &dc.refund_deadline),
1214 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_without_fee", 1214 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_without_fee",
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index 21a29e506..69c73746c 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -330,6 +330,8 @@ refund_by_coin_cb (void *cls,
330 * 330 *
331 * @param cls a `struct AggregationUnit` 331 * @param cls a `struct AggregationUnit`
332 * @param row_id identifies database entry 332 * @param row_id identifies database entry
333 * @param exchange_timestamp when did the deposit happen
334 * @param wallet_timestamp when did the contract happen
333 * @param merchant_pub public key of the merchant 335 * @param merchant_pub public key of the merchant
334 * @param coin_pub public key of the coin 336 * @param coin_pub public key of the coin
335 * @param amount_with_fee amount that was deposited including fee 337 * @param amount_with_fee amount that was deposited including fee
@@ -343,6 +345,8 @@ refund_by_coin_cb (void *cls,
343static enum GNUNET_DB_QueryStatus 345static enum GNUNET_DB_QueryStatus
344deposit_cb (void *cls, 346deposit_cb (void *cls,
345 uint64_t row_id, 347 uint64_t row_id,
348 struct GNUNET_TIME_Absolute exchange_timestamp,
349 struct GNUNET_TIME_Absolute wallet_timestamp,
346 const struct TALER_MerchantPublicKeyP *merchant_pub, 350 const struct TALER_MerchantPublicKeyP *merchant_pub,
347 const struct TALER_CoinSpendPublicKeyP *coin_pub, 351 const struct TALER_CoinSpendPublicKeyP *coin_pub,
348 const struct TALER_Amount *amount_with_fee, 352 const struct TALER_Amount *amount_with_fee,
@@ -358,6 +362,8 @@ deposit_cb (void *cls,
358 /* NOTE: potential optimization: use custom SQL API to not 362 /* NOTE: potential optimization: use custom SQL API to not
359 fetch this one: */ 363 fetch this one: */
360 (void) wire_deadline; /* already checked by SQL query */ 364 (void) wire_deadline; /* already checked by SQL query */
365 (void) exchange_timestamp;
366 (void) wallet_timestamp;
361 au->merchant_pub = *merchant_pub; 367 au->merchant_pub = *merchant_pub;
362 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 368 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
363 "Aggregator processing payment %s with amount %s\n", 369 "Aggregator processing payment %s with amount %s\n",
@@ -501,6 +507,8 @@ deposit_cb (void *cls,
501 * 507 *
502 * @param cls a `struct AggregationUnit` 508 * @param cls a `struct AggregationUnit`
503 * @param row_id identifies database entry 509 * @param row_id identifies database entry
510 * @param exchange_timestamp when did the exchange receive the deposit
511 * @param wallet_timestamp when did the wallet sign the contract
504 * @param merchant_pub public key of the merchant 512 * @param merchant_pub public key of the merchant
505 * @param coin_pub public key of the coin 513 * @param coin_pub public key of the coin
506 * @param amount_with_fee amount that was deposited including fee 514 * @param amount_with_fee amount that was deposited including fee
@@ -514,6 +522,8 @@ deposit_cb (void *cls,
514static enum GNUNET_DB_QueryStatus 522static enum GNUNET_DB_QueryStatus
515aggregate_cb (void *cls, 523aggregate_cb (void *cls,
516 uint64_t row_id, 524 uint64_t row_id,
525 struct GNUNET_TIME_Absolute exchange_timestamp,
526 struct GNUNET_TIME_Absolute wallet_timestamp,
517 const struct TALER_MerchantPublicKeyP *merchant_pub, 527 const struct TALER_MerchantPublicKeyP *merchant_pub,
518 const struct TALER_CoinSpendPublicKeyP *coin_pub, 528 const struct TALER_CoinSpendPublicKeyP *coin_pub,
519 const struct TALER_Amount *amount_with_fee, 529 const struct TALER_Amount *amount_with_fee,
@@ -529,6 +539,8 @@ aggregate_cb (void *cls,
529 /* NOTE: potential optimization: use custom SQL API to not 539 /* NOTE: potential optimization: use custom SQL API to not
530 fetch these: */ 540 fetch these: */
531 (void) wire_deadline; /* checked by SQL */ 541 (void) wire_deadline; /* checked by SQL */
542 (void) exchange_timestamp;
543 (void) wallet_timestamp;
532 (void) wire; /* must match */ 544 (void) wire; /* must match */
533 GNUNET_break (0 == GNUNET_memcmp (&au->merchant_pub, 545 GNUNET_break (0 == GNUNET_memcmp (&au->merchant_pub,
534 merchant_pub)); 546 merchant_pub));
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 65251863a..fe8fdf061 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -47,7 +47,7 @@
47 * @param coin_pub public key of the coin 47 * @param coin_pub public key of the coin
48 * @param h_wire hash of wire details 48 * @param h_wire hash of wire details
49 * @param h_contract_terms hash of contract details 49 * @param h_contract_terms hash of contract details
50 * @param timestamp client's timestamp 50 * @param exchange_timestamp exchange's timestamp
51 * @param refund_deadline until when this deposit be refunded 51 * @param refund_deadline until when this deposit be refunded
52 * @param merchant merchant public key 52 * @param merchant merchant public key
53 * @param amount_without_fee fraction of coin value to deposit, without the fee 53 * @param amount_without_fee fraction of coin value to deposit, without the fee
@@ -58,7 +58,7 @@ reply_deposit_success (struct MHD_Connection *connection,
58 const struct TALER_CoinSpendPublicKeyP *coin_pub, 58 const struct TALER_CoinSpendPublicKeyP *coin_pub,
59 const struct GNUNET_HashCode *h_wire, 59 const struct GNUNET_HashCode *h_wire,
60 const struct GNUNET_HashCode *h_contract_terms, 60 const struct GNUNET_HashCode *h_contract_terms,
61 struct GNUNET_TIME_Absolute timestamp, 61 struct GNUNET_TIME_Absolute exchange_timestamp,
62 struct GNUNET_TIME_Absolute refund_deadline, 62 struct GNUNET_TIME_Absolute refund_deadline,
63 const struct TALER_MerchantPublicKeyP *merchant, 63 const struct TALER_MerchantPublicKeyP *merchant,
64 const struct TALER_Amount *amount_without_fee) 64 const struct TALER_Amount *amount_without_fee)
@@ -70,7 +70,7 @@ reply_deposit_success (struct MHD_Connection *connection,
70 .purpose.size = htonl (sizeof (dc)), 70 .purpose.size = htonl (sizeof (dc)),
71 .h_contract_terms = *h_contract_terms, 71 .h_contract_terms = *h_contract_terms,
72 .h_wire = *h_wire, 72 .h_wire = *h_wire,
73 .timestamp = GNUNET_TIME_absolute_hton (timestamp), 73 .exchange_timestamp = GNUNET_TIME_absolute_hton (exchange_timestamp),
74 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline), 74 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
75 .coin_pub = *coin_pub, 75 .coin_pub = *coin_pub,
76 .merchant = *merchant 76 .merchant = *merchant
@@ -88,13 +88,16 @@ reply_deposit_success (struct MHD_Connection *connection,
88 TALER_EC_EXCHANGE_BAD_CONFIGURATION, 88 TALER_EC_EXCHANGE_BAD_CONFIGURATION,
89 "no keys"); 89 "no keys");
90 } 90 }
91 return TALER_MHD_reply_json_pack (connection, 91 return TALER_MHD_reply_json_pack (
92 MHD_HTTP_OK, 92 connection,
93 "{s:o, s:o}", 93 MHD_HTTP_OK,
94 "exchange_sig", 94 "{s:o, s:o, s:o}",
95 GNUNET_JSON_from_data_auto (&sig), 95 "exchange_timestamp",
96 "exchange_pub", 96 GNUNET_JSON_from_time_abs (exchange_timestamp),
97 GNUNET_JSON_from_data_auto (&pub)); 97 "exchange_sig",
98 GNUNET_JSON_from_data_auto (&sig),
99 "exchange_pub",
100 GNUNET_JSON_from_data_auto (&pub));
98} 101}
99 102
100 103
@@ -109,6 +112,11 @@ struct DepositContext
109 const struct TALER_EXCHANGEDB_Deposit *deposit; 112 const struct TALER_EXCHANGEDB_Deposit *deposit;
110 113
111 /** 114 /**
115 * Our timestamp (when we received the request).
116 */
117 struct GNUNET_TIME_Absolute exchange_timestamp;
118
119 /**
112 * Value of the coin. 120 * Value of the coin.
113 */ 121 */
114 struct TALER_Amount value; 122 struct TALER_Amount value;
@@ -117,12 +125,11 @@ struct DepositContext
117 125
118 126
119/** 127/**
120 * Execute database transaction for /deposit. Runs the transaction 128 * Check if /deposit is already in the database. IF it returns a non-error
121 * logic; IF it returns a non-error code, the transaction logic MUST 129 * code, the transaction logic MUST NOT queue a MHD response. IF it returns
122 * NOT queue a MHD response. IF it returns an hard error, the 130 * an hard error, the transaction logic MUST queue a MHD response and set @a
123 * transaction logic MUST queue a MHD response and set @a mhd_ret. IF 131 * mhd_ret. We do return a "hard" error also if we found the deposit in the
124 * it returns the soft error code, the function MAY be called again to 132 * database and generated a regular response.
125 * retry and MUST not queue a MHD response.
126 * 133 *
127 * @param cls a `struct DepositContext` 134 * @param cls a `struct DepositContext`
128 * @param connection MHD request context 135 * @param connection MHD request context
@@ -131,20 +138,22 @@ struct DepositContext
131 * @return transaction status 138 * @return transaction status
132 */ 139 */
133static enum GNUNET_DB_QueryStatus 140static enum GNUNET_DB_QueryStatus
134deposit_transaction (void *cls, 141deposit_precheck (void *cls,
135 struct MHD_Connection *connection, 142 struct MHD_Connection *connection,
136 struct TALER_EXCHANGEDB_Session *session, 143 struct TALER_EXCHANGEDB_Session *session,
137 MHD_RESULT *mhd_ret) 144 MHD_RESULT *mhd_ret)
138{ 145{
139 struct DepositContext *dc = cls; 146 struct DepositContext *dc = cls;
140 const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit; 147 const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
141 struct TALER_Amount spent; 148 struct TALER_Amount deposit_fee;
142 enum GNUNET_DB_QueryStatus qs; 149 enum GNUNET_DB_QueryStatus qs;
143 150
144 qs = TEH_plugin->have_deposit (TEH_plugin->cls, 151 qs = TEH_plugin->have_deposit (TEH_plugin->cls,
145 session, 152 session,
146 deposit, 153 deposit,
147 GNUNET_YES /* check refund deadline */); 154 GNUNET_YES /* check refund deadline */,
155 &deposit_fee,
156 &dc->exchange_timestamp);
148 if (qs < 0) 157 if (qs < 0)
149 { 158 {
150 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 159 if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -166,12 +175,12 @@ deposit_transaction (void *cls,
166 GNUNET_assert (0 <= 175 GNUNET_assert (0 <=
167 TALER_amount_subtract (&amount_without_fee, 176 TALER_amount_subtract (&amount_without_fee,
168 &deposit->amount_with_fee, 177 &deposit->amount_with_fee,
169 &deposit->deposit_fee)); 178 &deposit_fee));
170 *mhd_ret = reply_deposit_success (connection, 179 *mhd_ret = reply_deposit_success (connection,
171 &deposit->coin.coin_pub, 180 &deposit->coin.coin_pub,
172 &deposit->h_wire, 181 &deposit->h_wire,
173 &deposit->h_contract_terms, 182 &deposit->h_contract_terms,
174 deposit->timestamp, 183 dc->exchange_timestamp,
175 deposit->refund_deadline, 184 deposit->refund_deadline,
176 &deposit->merchant_pub, 185 &deposit->merchant_pub,
177 &amount_without_fee); 186 &amount_without_fee);
@@ -179,6 +188,44 @@ deposit_transaction (void *cls,
179 never try again. */ 188 never try again. */
180 return GNUNET_DB_STATUS_HARD_ERROR; 189 return GNUNET_DB_STATUS_HARD_ERROR;
181 } 190 }
191 return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
192}
193
194
195/**
196 * Execute database transaction for /deposit. Runs the transaction
197 * logic; IF it returns a non-error code, the transaction logic MUST
198 * NOT queue a MHD response. IF it returns an hard error, the
199 * transaction logic MUST queue a MHD response and set @a mhd_ret. IF
200 * it returns the soft error code, the function MAY be called again to
201 * retry and MUST not queue a MHD response.
202 *
203 * @param cls a `struct DepositContext`
204 * @param connection MHD request context
205 * @param session database session and transaction to use
206 * @param[out] mhd_ret set to MHD status on error
207 * @return transaction status
208 */
209static enum GNUNET_DB_QueryStatus
210deposit_transaction (void *cls,
211 struct MHD_Connection *connection,
212 struct TALER_EXCHANGEDB_Session *session,
213 MHD_RESULT *mhd_ret)
214{
215 struct DepositContext *dc = cls;
216 const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
217 struct TALER_Amount spent;
218 enum GNUNET_DB_QueryStatus qs;
219
220 /* Theoretically, someone other threat may have received
221 and committed the deposit in the meantime. Check now
222 that we are in the transaction scope. */
223 qs = deposit_precheck (cls,
224 connection,
225 session,
226 mhd_ret);
227 if (qs < 0)
228 return qs;
182 229
183 /* Start with fee for THIS transaction */ 230 /* Start with fee for THIS transaction */
184 spent = deposit->amount_with_fee; 231 spent = deposit->amount_with_fee;
@@ -238,6 +285,7 @@ deposit_transaction (void *cls,
238 } 285 }
239 qs = TEH_plugin->insert_deposit (TEH_plugin->cls, 286 qs = TEH_plugin->insert_deposit (TEH_plugin->cls,
240 session, 287 session,
288 dc->exchange_timestamp,
241 deposit); 289 deposit);
242 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 290 if (GNUNET_DB_STATUS_HARD_ERROR == qs)
243 { 291 {
@@ -252,45 +300,6 @@ deposit_transaction (void *cls,
252 300
253 301
254/** 302/**
255 * Check that @a ts is reasonably close to our own RTC.
256 *
257 * @param ts timestamp to check
258 * @return #GNUNET_OK if @a ts is reasonable
259 */
260static int
261check_timestamp_current (struct GNUNET_TIME_Absolute ts)
262{
263 struct GNUNET_TIME_Relative r;
264 struct GNUNET_TIME_Relative tolerance;
265
266 /* Let's be VERY generous (after all, this is basically about
267 which year the deposit counts for in terms of tax purposes) */
268 tolerance = GNUNET_TIME_UNIT_MONTHS;
269 r = GNUNET_TIME_absolute_get_duration (ts);
270 if (r.rel_value_us > tolerance.rel_value_us)
271 {
272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273 "Deposit timestamp too old: %llu vs %llu > %llu\n",
274 (unsigned long long) ts.abs_value_us,
275 (unsigned long long) GNUNET_TIME_absolute_get ().abs_value_us,
276 (unsigned long long) tolerance.rel_value_us);
277 return GNUNET_SYSERR;
278 }
279 r = GNUNET_TIME_absolute_get_remaining (ts);
280 if (r.rel_value_us > tolerance.rel_value_us)
281 {
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Deposit timestamp too new: %llu vs %llu < - %llu\n",
284 (unsigned long long) ts.abs_value_us,
285 (unsigned long long) GNUNET_TIME_absolute_get ().abs_value_us,
286 (unsigned long long) tolerance.rel_value_us);
287 return GNUNET_SYSERR;
288 }
289 return GNUNET_OK;
290}
291
292
293/**
294 * Handle a "/coins/$COIN_PUB/deposit" request. Parses the JSON, and, if 303 * Handle a "/coins/$COIN_PUB/deposit" request. Parses the JSON, and, if
295 * successful, passes the JSON data to #deposit_transaction() to 304 * successful, passes the JSON data to #deposit_transaction() to
296 * further check the details of the operation specified. If everything checks 305 * further check the details of the operation specified. If everything checks
@@ -367,17 +376,6 @@ TEH_handler_deposit (struct MHD_Connection *connection,
367 TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE, 376 TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
368 "refund_deadline"); 377 "refund_deadline");
369 } 378 }
370
371 if (GNUNET_OK !=
372 check_timestamp_current (deposit.timestamp))
373 {
374 GNUNET_break_op (0);
375 GNUNET_JSON_parse_free (spec);
376 return TALER_MHD_reply_with_error (connection,
377 MHD_HTTP_BAD_REQUEST,
378 TALER_EC_DEPOSIT_INVALID_TIMESTAMP,
379 "timestamp");
380 }
381 if (GNUNET_OK != 379 if (GNUNET_OK !=
382 TALER_JSON_merchant_wire_signature_hash (wire, 380 TALER_JSON_merchant_wire_signature_hash (wire,
383 &my_h_wire)) 381 &my_h_wire))
@@ -401,6 +399,26 @@ TEH_handler_deposit (struct MHD_Connection *connection,
401 "h_wire"); 399 "h_wire");
402 } 400 }
403 401
402 /* Check for idempotency: did we get this request before? */
403 dc.deposit = &deposit;
404 {
405 MHD_RESULT mhd_ret;
406
407 if (GNUNET_OK !=
408 TEH_DB_run_transaction (connection,
409 "precheck deposit",
410 &mhd_ret,
411 &deposit_precheck,
412 &dc))
413 {
414 GNUNET_JSON_parse_free (spec);
415 return mhd_ret;
416 }
417 }
418
419 /* new deposit */
420 dc.exchange_timestamp = GNUNET_TIME_absolute_get ();
421 (void) GNUNET_TIME_round_abs (&dc.exchange_timestamp);
404 /* check denomination exists and is valid */ 422 /* check denomination exists and is valid */
405 { 423 {
406 struct TEH_KS_StateHandle *key_state; 424 struct TEH_KS_StateHandle *key_state;
@@ -408,7 +426,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
408 enum TALER_ErrorCode ec; 426 enum TALER_ErrorCode ec;
409 unsigned int hc; 427 unsigned int hc;
410 428
411 key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); 429 key_state = TEH_KS_acquire (dc.exchange_timestamp);
412 if (NULL == key_state) 430 if (NULL == key_state)
413 { 431 {
414 TALER_LOG_ERROR ("Lacking keys to operate\n"); 432 TALER_LOG_ERROR ("Lacking keys to operate\n");
@@ -502,7 +520,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
502 .purpose.size = htonl (sizeof (dr)), 520 .purpose.size = htonl (sizeof (dr)),
503 .h_contract_terms = deposit.h_contract_terms, 521 .h_contract_terms = deposit.h_contract_terms,
504 .h_wire = deposit.h_wire, 522 .h_wire = deposit.h_wire,
505 .timestamp = GNUNET_TIME_absolute_hton (deposit.timestamp), 523 .wallet_timestamp = GNUNET_TIME_absolute_hton (deposit.timestamp),
506 .refund_deadline = GNUNET_TIME_absolute_hton (deposit.refund_deadline), 524 .refund_deadline = GNUNET_TIME_absolute_hton (deposit.refund_deadline),
507 .merchant = deposit.merchant_pub, 525 .merchant = deposit.merchant_pub,
508 .coin_pub = deposit.coin.coin_pub 526 .coin_pub = deposit.coin.coin_pub
@@ -528,7 +546,6 @@ TEH_handler_deposit (struct MHD_Connection *connection,
528 } 546 }
529 547
530 /* execute transaction */ 548 /* execute transaction */
531 dc.deposit = &deposit;
532 { 549 {
533 MHD_RESULT mhd_ret; 550 MHD_RESULT mhd_ret;
534 551
@@ -557,7 +574,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
557 &deposit.coin.coin_pub, 574 &deposit.coin.coin_pub,
558 &deposit.h_wire, 575 &deposit.h_wire,
559 &deposit.h_contract_terms, 576 &deposit.h_contract_terms,
560 deposit.timestamp, 577 dc.exchange_timestamp,
561 deposit.refund_deadline, 578 deposit.refund_deadline,
562 &deposit.merchant_pub, 579 &deposit.merchant_pub,
563 &amount_without_fee); 580 &amount_without_fee);
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index 7924ad54c..f65951614 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -66,7 +66,7 @@ TEH_RESPONSE_compile_transaction_history (
66 .purpose.size = htonl (sizeof (dr)), 66 .purpose.size = htonl (sizeof (dr)),
67 .h_contract_terms = deposit->h_contract_terms, 67 .h_contract_terms = deposit->h_contract_terms,
68 .h_wire = deposit->h_wire, 68 .h_wire = deposit->h_wire,
69 .timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp), 69 .wallet_timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp),
70 .refund_deadline = GNUNET_TIME_absolute_hton ( 70 .refund_deadline = GNUNET_TIME_absolute_hton (
71 deposit->refund_deadline), 71 deposit->refund_deadline),
72 .merchant = deposit->merchant_pub, 72 .merchant = deposit->merchant_pub,
diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql
index bec9af5ba..ad05e7797 100644
--- a/src/exchangedb/exchange-0001.sql
+++ b/src/exchangedb/exchange-0001.sql
@@ -254,7 +254,8 @@ CREATE TABLE IF NOT EXISTS deposits
254 ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE 254 ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
255 ,amount_with_fee_val INT8 NOT NULL 255 ,amount_with_fee_val INT8 NOT NULL
256 ,amount_with_fee_frac INT4 NOT NULL 256 ,amount_with_fee_frac INT4 NOT NULL
257 ,timestamp INT8 NOT NULL 257 ,wallet_timestamp INT8 NOT NULL
258 ,exchange_timestamp INT8 NOT NULL
258 ,refund_deadline INT8 NOT NULL 259 ,refund_deadline INT8 NOT NULL
259 ,wire_deadline INT8 NOT NULL 260 ,wire_deadline INT8 NOT NULL
260 ,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32) 261 ,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 5bd674b2d..93577feb4 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -796,7 +796,7 @@ postgres_get_session (void *cls)
796 "(coin_pub" 796 "(coin_pub"
797 ",amount_with_fee_val" 797 ",amount_with_fee_val"
798 ",amount_with_fee_frac" 798 ",amount_with_fee_frac"
799 ",timestamp" 799 ",wallet_timestamp"
800 ",refund_deadline" 800 ",refund_deadline"
801 ",wire_deadline" 801 ",wire_deadline"
802 ",merchant_pub" 802 ",merchant_pub"
@@ -804,22 +804,28 @@ postgres_get_session (void *cls)
804 ",h_wire" 804 ",h_wire"
805 ",coin_sig" 805 ",coin_sig"
806 ",wire" 806 ",wire"
807 ",exchange_timestamp"
807 ") VALUES " 808 ") VALUES "
808 "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10," 809 "($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
809 " $11);", 810 " $11, $12);",
810 11), 811 12),
811 /* Fetch an existing deposit request, used to ensure idempotency 812 /* Fetch an existing deposit request, used to ensure idempotency
812 during /deposit processing. Used in #postgres_have_deposit(). */ 813 during /deposit processing. Used in #postgres_have_deposit(). */
813 GNUNET_PQ_make_prepare ("get_deposit", 814 GNUNET_PQ_make_prepare ("get_deposit",
814 "SELECT" 815 "SELECT"
815 " amount_with_fee_val" 816 " amount_with_fee_val"
816 ",amount_with_fee_frac" 817 ",amount_with_fee_frac"
817 ",timestamp" 818 ",denominations.fee_deposit_val"
819 ",denominations.fee_deposit_frac"
820 ",wallet_timestamp"
821 ",exchange_timestamp"
818 ",refund_deadline" 822 ",refund_deadline"
819 ",wire_deadline" 823 ",wire_deadline"
820 ",h_contract_terms" 824 ",h_contract_terms"
821 ",h_wire" 825 ",h_wire"
822 " FROM deposits" 826 " FROM deposits"
827 " JOIN known_coins USING (coin_pub)"
828 " JOIN denominations USING (denom_pub_hash)"
823 " WHERE ((coin_pub=$1)" 829 " WHERE ((coin_pub=$1)"
824 " AND (merchant_pub=$3)" 830 " AND (merchant_pub=$3)"
825 " AND (h_contract_terms=$2))" 831 " AND (h_contract_terms=$2))"
@@ -830,7 +836,8 @@ postgres_get_session (void *cls)
830 "SELECT" 836 "SELECT"
831 " amount_with_fee_val" 837 " amount_with_fee_val"
832 ",amount_with_fee_frac" 838 ",amount_with_fee_frac"
833 ",timestamp" 839 ",wallet_timestamp"
840 ",exchange_timestamp"
834 ",merchant_pub" 841 ",merchant_pub"
835 ",denom.denom_pub" 842 ",denom.denom_pub"
836 ",coin_pub" 843 ",coin_pub"
@@ -881,6 +888,8 @@ postgres_get_session (void *cls)
881 ",wire" 888 ",wire"
882 ",merchant_pub" 889 ",merchant_pub"
883 ",coin_pub" 890 ",coin_pub"
891 ",exchange_timestamp"
892 ",wallet_timestamp"
884 " FROM deposits" 893 " FROM deposits"
885 " JOIN known_coins USING (coin_pub)" 894 " JOIN known_coins USING (coin_pub)"
886 " JOIN denominations denom USING (denom_pub_hash)" 895 " JOIN denominations denom USING (denom_pub_hash)"
@@ -900,6 +909,8 @@ postgres_get_session (void *cls)
900 ",denom.fee_deposit_val" 909 ",denom.fee_deposit_val"
901 ",denom.fee_deposit_frac" 910 ",denom.fee_deposit_frac"
902 ",wire_deadline" 911 ",wire_deadline"
912 ",exchange_timestamp"
913 ",wallet_timestamp"
903 ",h_contract_terms" 914 ",h_contract_terms"
904 ",coin_pub" 915 ",coin_pub"
905 " FROM deposits" 916 " FROM deposits"
@@ -945,7 +956,7 @@ postgres_get_session (void *cls)
945 ",amount_with_fee_frac" 956 ",amount_with_fee_frac"
946 ",denom.fee_deposit_val" 957 ",denom.fee_deposit_val"
947 ",denom.fee_deposit_frac" 958 ",denom.fee_deposit_frac"
948 ",timestamp" 959 ",wallet_timestamp"
949 ",refund_deadline" 960 ",refund_deadline"
950 ",wire_deadline" 961 ",wire_deadline"
951 ",merchant_pub" 962 ",merchant_pub"
@@ -2571,6 +2582,8 @@ postgres_get_reserve_history (void *cls,
2571 * @param session database connection 2582 * @param session database connection
2572 * @param deposit deposit to search for 2583 * @param deposit deposit to search for
2573 * @param check_extras whether to check extra fields match or not 2584 * @param check_extras whether to check extra fields match or not
2585 * @param[out] deposit_fee set to the deposit fee the exchange charged
2586 * @param[out] exchange_timestamp set to the time when the exchange received the deposit
2574 * @return 1 if we know this operation, 2587 * @return 1 if we know this operation,
2575 * 0 if this exact deposit is unknown to us, 2588 * 0 if this exact deposit is unknown to us,
2576 * otherwise transaction error status 2589 * otherwise transaction error status
@@ -2579,7 +2592,9 @@ static enum GNUNET_DB_QueryStatus
2579postgres_have_deposit (void *cls, 2592postgres_have_deposit (void *cls,
2580 struct TALER_EXCHANGEDB_Session *session, 2593 struct TALER_EXCHANGEDB_Session *session,
2581 const struct TALER_EXCHANGEDB_Deposit *deposit, 2594 const struct TALER_EXCHANGEDB_Deposit *deposit,
2582 int check_extras) 2595 int check_extras,
2596 struct TALER_Amount *deposit_fee,
2597 struct GNUNET_TIME_Absolute *exchange_timestamp)
2583{ 2598{
2584 struct PostgresClosure *pg = cls; 2599 struct PostgresClosure *pg = cls;
2585 struct GNUNET_PQ_QueryParam params[] = { 2600 struct GNUNET_PQ_QueryParam params[] = {
@@ -2592,12 +2607,16 @@ postgres_have_deposit (void *cls,
2592 struct GNUNET_PQ_ResultSpec rs[] = { 2607 struct GNUNET_PQ_ResultSpec rs[] = {
2593 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", 2608 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
2594 &deposit2.amount_with_fee), 2609 &deposit2.amount_with_fee),
2595 TALER_PQ_result_spec_absolute_time ("timestamp", 2610 TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
2596 &deposit2.timestamp), 2611 &deposit2.timestamp),
2612 TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
2613 exchange_timestamp),
2597 TALER_PQ_result_spec_absolute_time ("refund_deadline", 2614 TALER_PQ_result_spec_absolute_time ("refund_deadline",
2598 &deposit2.refund_deadline), 2615 &deposit2.refund_deadline),
2599 TALER_PQ_result_spec_absolute_time ("wire_deadline", 2616 TALER_PQ_result_spec_absolute_time ("wire_deadline",
2600 &deposit2.wire_deadline), 2617 &deposit2.wire_deadline),
2618 TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
2619 deposit_fee),
2601 GNUNET_PQ_result_spec_auto_from_type ("h_wire", 2620 GNUNET_PQ_result_spec_auto_from_type ("h_wire",
2602 &deposit2.h_wire), 2621 &deposit2.h_wire),
2603 GNUNET_PQ_result_spec_end 2622 GNUNET_PQ_result_spec_end
@@ -2776,6 +2795,8 @@ postgres_get_ready_deposit (void *cls,
2776 struct TALER_Amount amount_with_fee; 2795 struct TALER_Amount amount_with_fee;
2777 struct TALER_Amount deposit_fee; 2796 struct TALER_Amount deposit_fee;
2778 struct GNUNET_TIME_Absolute wire_deadline; 2797 struct GNUNET_TIME_Absolute wire_deadline;
2798 struct GNUNET_TIME_Absolute wallet_timestamp;
2799 struct GNUNET_TIME_Absolute exchange_timestamp;
2779 struct GNUNET_HashCode h_contract_terms; 2800 struct GNUNET_HashCode h_contract_terms;
2780 struct TALER_MerchantPublicKeyP merchant_pub; 2801 struct TALER_MerchantPublicKeyP merchant_pub;
2781 struct TALER_CoinSpendPublicKeyP coin_pub; 2802 struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -2788,6 +2809,10 @@ postgres_get_ready_deposit (void *cls,
2788 &amount_with_fee), 2809 &amount_with_fee),
2789 TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", 2810 TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
2790 &deposit_fee), 2811 &deposit_fee),
2812 TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
2813 &exchange_timestamp),
2814 TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
2815 &wallet_timestamp),
2791 TALER_PQ_result_spec_absolute_time ("wire_deadline", 2816 TALER_PQ_result_spec_absolute_time ("wire_deadline",
2792 &wire_deadline), 2817 &wire_deadline),
2793 GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", 2818 GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
@@ -2817,6 +2842,8 @@ postgres_get_ready_deposit (void *cls,
2817 2842
2818 qs = deposit_cb (deposit_cb_cls, 2843 qs = deposit_cb (deposit_cb_cls,
2819 serial_id, 2844 serial_id,
2845 exchange_timestamp,
2846 wallet_timestamp,
2820 &merchant_pub, 2847 &merchant_pub,
2821 &coin_pub, 2848 &coin_pub,
2822 &amount_with_fee, 2849 &amount_with_fee,
@@ -2898,6 +2925,8 @@ match_deposit_cb (void *cls,
2898 { 2925 {
2899 struct TALER_Amount amount_with_fee; 2926 struct TALER_Amount amount_with_fee;
2900 struct TALER_Amount deposit_fee; 2927 struct TALER_Amount deposit_fee;
2928 struct GNUNET_TIME_Absolute exchange_timestamp;
2929 struct GNUNET_TIME_Absolute wallet_timestamp;
2901 struct GNUNET_TIME_Absolute wire_deadline; 2930 struct GNUNET_TIME_Absolute wire_deadline;
2902 struct GNUNET_HashCode h_contract_terms; 2931 struct GNUNET_HashCode h_contract_terms;
2903 struct TALER_CoinSpendPublicKeyP coin_pub; 2932 struct TALER_CoinSpendPublicKeyP coin_pub;
@@ -2912,6 +2941,10 @@ match_deposit_cb (void *cls,
2912 &deposit_fee), 2941 &deposit_fee),
2913 TALER_PQ_result_spec_absolute_time ("wire_deadline", 2942 TALER_PQ_result_spec_absolute_time ("wire_deadline",
2914 &wire_deadline), 2943 &wire_deadline),
2944 TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
2945 &exchange_timestamp),
2946 TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
2947 &wallet_timestamp),
2915 GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", 2948 GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
2916 &h_contract_terms), 2949 &h_contract_terms),
2917 GNUNET_PQ_result_spec_auto_from_type ("coin_pub", 2950 GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
@@ -2930,6 +2963,8 @@ match_deposit_cb (void *cls,
2930 } 2963 }
2931 qs = mdc->deposit_cb (mdc->deposit_cb_cls, 2964 qs = mdc->deposit_cb (mdc->deposit_cb_cls,
2932 serial_id, 2965 serial_id,
2966 exchange_timestamp,
2967 wallet_timestamp,
2933 mdc->merchant_pub, 2968 mdc->merchant_pub,
2934 &coin_pub, 2969 &coin_pub,
2935 &amount_with_fee, 2970 &amount_with_fee,
@@ -3210,12 +3245,14 @@ postgres_ensure_coin_known (void *cls,
3210 * 3245 *
3211 * @param cls the `struct PostgresClosure` with the plugin-specific state 3246 * @param cls the `struct PostgresClosure` with the plugin-specific state
3212 * @param session connection to the database 3247 * @param session connection to the database
3248 * @param exchange_timestamp time the exchange received the deposit request
3213 * @param deposit deposit information to store 3249 * @param deposit deposit information to store
3214 * @return query result status 3250 * @return query result status
3215 */ 3251 */
3216static enum GNUNET_DB_QueryStatus 3252static enum GNUNET_DB_QueryStatus
3217postgres_insert_deposit (void *cls, 3253postgres_insert_deposit (void *cls,
3218 struct TALER_EXCHANGEDB_Session *session, 3254 struct TALER_EXCHANGEDB_Session *session,
3255 struct GNUNET_TIME_Absolute exchange_timestamp,
3219 const struct TALER_EXCHANGEDB_Deposit *deposit) 3256 const struct TALER_EXCHANGEDB_Deposit *deposit)
3220{ 3257{
3221 struct GNUNET_PQ_QueryParam params[] = { 3258 struct GNUNET_PQ_QueryParam params[] = {
@@ -3229,6 +3266,7 @@ postgres_insert_deposit (void *cls,
3229 GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire), 3266 GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire),
3230 GNUNET_PQ_query_param_auto_from_type (&deposit->csig), 3267 GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
3231 TALER_PQ_query_param_json (deposit->receiver_wire_account), 3268 TALER_PQ_query_param_json (deposit->receiver_wire_account),
3269 TALER_PQ_query_param_absolute_time (&exchange_timestamp),
3232 GNUNET_PQ_query_param_end 3270 GNUNET_PQ_query_param_end
3233 }; 3271 };
3234 3272
@@ -4042,7 +4080,7 @@ add_coin_deposit (void *cls,
4042 &deposit->amount_with_fee), 4080 &deposit->amount_with_fee),
4043 TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", 4081 TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
4044 &deposit->deposit_fee), 4082 &deposit->deposit_fee),
4045 TALER_PQ_result_spec_absolute_time ("timestamp", 4083 TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
4046 &deposit->timestamp), 4084 &deposit->timestamp),
4047 TALER_PQ_result_spec_absolute_time ("refund_deadline", 4085 TALER_PQ_result_spec_absolute_time ("refund_deadline",
4048 &deposit->refund_deadline), 4086 &deposit->refund_deadline),
@@ -5462,14 +5500,17 @@ deposit_serial_helper_cb (void *cls,
5462 for (unsigned int i = 0; i<num_results; i++) 5500 for (unsigned int i = 0; i<num_results; i++)
5463 { 5501 {
5464 struct TALER_EXCHANGEDB_Deposit deposit; 5502 struct TALER_EXCHANGEDB_Deposit deposit;
5503 struct GNUNET_TIME_Absolute exchange_timestamp;
5465 struct TALER_DenominationPublicKey denom_pub; 5504 struct TALER_DenominationPublicKey denom_pub;
5466 uint8_t done = 0; 5505 uint8_t done = 0;
5467 uint64_t rowid; 5506 uint64_t rowid;
5468 struct GNUNET_PQ_ResultSpec rs[] = { 5507 struct GNUNET_PQ_ResultSpec rs[] = {
5469 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", 5508 TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
5470 &deposit.amount_with_fee), 5509 &deposit.amount_with_fee),
5471 TALER_PQ_result_spec_absolute_time ("timestamp", 5510 TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
5472 &deposit.timestamp), 5511 &deposit.timestamp),
5512 TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
5513 &exchange_timestamp),
5473 GNUNET_PQ_result_spec_auto_from_type ("merchant_pub", 5514 GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
5474 &deposit.merchant_pub), 5515 &deposit.merchant_pub),
5475 GNUNET_PQ_result_spec_rsa_public_key ("denom_pub", 5516 GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
@@ -5505,6 +5546,7 @@ deposit_serial_helper_cb (void *cls,
5505 } 5546 }
5506 ret = dsc->cb (dsc->cb_cls, 5547 ret = dsc->cb (dsc->cb_cls,
5507 rowid, 5548 rowid,
5549 exchange_timestamp,
5508 deposit.timestamp, 5550 deposit.timestamp,
5509 &deposit.merchant_pub, 5551 &deposit.merchant_pub,
5510 &denom_pub, 5552 &denom_pub,
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index eea484e94..fe3ed7854 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -833,6 +833,8 @@ static uint64_t deposit_rowid;
833 * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *` 833 * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *`
834 * @param rowid unique ID for the deposit in our DB, used for marking 834 * @param rowid unique ID for the deposit in our DB, used for marking
835 * it as 'tiny' or 'done' 835 * it as 'tiny' or 'done'
836 * @param exchange_timestamp when did the deposit happen
837 * @param wallet_timestamp when did the wallet sign the contract
836 * @param merchant_pub public key of the merchant 838 * @param merchant_pub public key of the merchant
837 * @param coin_pub public key of the coin 839 * @param coin_pub public key of the coin
838 * @param amount_with_fee amount that was deposited including fee 840 * @param amount_with_fee amount that was deposited including fee
@@ -846,6 +848,8 @@ static uint64_t deposit_rowid;
846static enum GNUNET_DB_QueryStatus 848static enum GNUNET_DB_QueryStatus
847deposit_cb (void *cls, 849deposit_cb (void *cls,
848 uint64_t rowid, 850 uint64_t rowid,
851 struct GNUNET_TIME_Absolute exchange_timestamp,
852 struct GNUNET_TIME_Absolute wallet_timestamp,
849 const struct TALER_MerchantPublicKeyP *merchant_pub, 853 const struct TALER_MerchantPublicKeyP *merchant_pub,
850 const struct TALER_CoinSpendPublicKeyP *coin_pub, 854 const struct TALER_CoinSpendPublicKeyP *coin_pub,
851 const struct TALER_Amount *amount_with_fee, 855 const struct TALER_Amount *amount_with_fee,
@@ -890,7 +894,8 @@ deposit_cb (void *cls,
890 * 894 *
891 * @param cls closure 895 * @param cls closure
892 * @param rowid unique serial ID for the deposit in our DB 896 * @param rowid unique serial ID for the deposit in our DB
893 * @param timestamp when did the deposit happen 897 * @param exchange_timestamp when did the deposit happen
898 * @param wallet_timestamp when did the wallet sign the contract
894 * @param merchant_pub public key of the merchant 899 * @param merchant_pub public key of the merchant
895 * @param denom_pub denomination of the @a coin_pub 900 * @param denom_pub denomination of the @a coin_pub
896 * @param coin_pub public key of the coin 901 * @param coin_pub public key of the coin
@@ -908,7 +913,8 @@ deposit_cb (void *cls,
908static int 913static int
909audit_deposit_cb (void *cls, 914audit_deposit_cb (void *cls,
910 uint64_t rowid, 915 uint64_t rowid,
911 struct GNUNET_TIME_Absolute timestamp, 916 struct GNUNET_TIME_Absolute exchange_timestamp,
917 struct GNUNET_TIME_Absolute wallet_timestamp,
912 const struct TALER_MerchantPublicKeyP *merchant_pub, 918 const struct TALER_MerchantPublicKeyP *merchant_pub,
913 const struct TALER_DenominationPublicKey *denom_pub, 919 const struct TALER_DenominationPublicKey *denom_pub,
914 const struct TALER_CoinSpendPublicKeyP *coin_pub, 920 const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -1878,15 +1884,27 @@ run (void *cls)
1878 plugin->ensure_coin_known (plugin->cls, 1884 plugin->ensure_coin_known (plugin->cls,
1879 session, 1885 session,
1880 &deposit.coin)); 1886 &deposit.coin));
1881 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1887 {
1882 plugin->insert_deposit (plugin->cls, 1888 struct GNUNET_TIME_Absolute now;
1889 struct GNUNET_TIME_Absolute r;
1890 struct TALER_Amount deposit_fee;
1891
1892 now = GNUNET_TIME_absolute_get ();
1893 GNUNET_TIME_round_abs (&now);
1894 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
1895 plugin->insert_deposit (plugin->cls,
1896 session,
1897 now,
1898 &deposit));
1899 FAILIF (1 !=
1900 plugin->have_deposit (plugin->cls,
1883 session, 1901 session,
1884 &deposit)); 1902 &deposit,
1885 FAILIF (1 != 1903 GNUNET_YES,
1886 plugin->have_deposit (plugin->cls, 1904 &deposit_fee,
1887 session, 1905 &r));
1888 &deposit, 1906 FAILIF (now.abs_value_us != r.abs_value_us);
1889 GNUNET_YES)); 1907 }
1890 { 1908 {
1891 struct GNUNET_TIME_Absolute start_range; 1909 struct GNUNET_TIME_Absolute start_range;
1892 struct GNUNET_TIME_Absolute end_range; 1910 struct GNUNET_TIME_Absolute end_range;
@@ -1983,18 +2001,27 @@ run (void *cls)
1983 session, 2001 session,
1984 "test-2")); 2002 "test-2"));
1985 RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */ 2003 RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */
1986 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2004 {
1987 plugin->have_deposit (plugin->cls, 2005 struct GNUNET_TIME_Absolute r;
1988 session, 2006 struct TALER_Amount deposit_fee;
1989 &deposit2, 2007
1990 GNUNET_YES)); 2008 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
1991 deposit2.merchant_pub = deposit.merchant_pub; 2009 plugin->have_deposit (plugin->cls,
1992 RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */ 2010 session,
1993 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2011 &deposit2,
1994 plugin->have_deposit (plugin->cls, 2012 GNUNET_YES,
1995 session, 2013 &deposit_fee,
1996 &deposit2, 2014 &r));
1997 GNUNET_YES)); 2015 deposit2.merchant_pub = deposit.merchant_pub;
2016 RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
2017 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
2018 plugin->have_deposit (plugin->cls,
2019 session,
2020 &deposit2,
2021 GNUNET_YES,
2022 &deposit_fee,
2023 &r));
2024 }
1998 FAILIF (GNUNET_OK != 2025 FAILIF (GNUNET_OK !=
1999 test_melting (session)); 2026 test_melting (session));
2000 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2027 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h
index 9a7f6ed7a..7c58e654e 100644
--- a/src/include/taler_auditordb_plugin.h
+++ b/src/include/taler_auditordb_plugin.h
@@ -300,9 +300,9 @@ struct TALER_AUDITORDB_DepositConfirmation
300 struct GNUNET_HashCode h_wire; 300 struct GNUNET_HashCode h_wire;
301 301
302 /** 302 /**
303 * Time when this confirmation was generated. 303 * Time when this deposit confirmation was generated by the exchange.
304 */ 304 */
305 struct GNUNET_TIME_Absolute timestamp; 305 struct GNUNET_TIME_Absolute exchange_timestamp;
306 306
307 /** 307 /**
308 * How much time does the @e merchant have to issue a refund 308 * How much time does the @e merchant have to issue a refund
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index 74660303d..eded23339 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -1542,73 +1542,92 @@ enum TALER_ErrorCode
1542 * This response is provided with HTTP status code 1542 * This response is provided with HTTP status code
1543 * #MHD_HTTP_SERVICE_UNAVAILABLE. 1543 * #MHD_HTTP_SERVICE_UNAVAILABLE.
1544 */ 1544 */
1545 TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT = 2400, 1545 TALER_EC_POST_TRANSFERS_EXCHANGE_TIMEOUT = 2400,
1546 1546
1547 /** 1547 /**
1548 * We failed to obtain an acceptable /keys response from the exchange 1548 * We failed to obtain an acceptable /keys response from the exchange
1549 * for the /track/transfer request. This response is provided with 1549 * for the /track/transfer request. This response is provided with
1550 * HTTP status code #MHD_HTTP_FAILED_DEPENDENCY. 1550 * HTTP status code #MHD_HTTP_FAILED_DEPENDENCY.
1551 */ 1551 */
1552 TALER_EC_TRACK_TRANSFER_EXCHANGE_KEYS_FAILURE = 2401, 1552 TALER_EC_POST_TRANSFERS_EXCHANGE_KEYS_FAILURE = 2401,
1553 1553
1554 /** 1554 /**
1555 * We failed to persist coin wire transfer information in our merchant 1555 * We failed to persist coin wire transfer information in our merchant
1556 * database. The response is provided with HTTP status code 1556 * database. The response is provided with HTTP status code
1557 * #MHD_HTTP_INTERNAL_SERVER_ERROR. 1557 * #MHD_HTTP_INTERNAL_SERVER_ERROR.
1558 */ 1558 */
1559 TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR = 2402, 1559 TALER_EC_POST_TRANSFERS_DB_STORE_COIN_ERROR = 2402,
1560 1560
1561 /** 1561 /**
1562 * We internally failed to execute the /track/transfer request. The 1562 * We internally failed to execute the /track/transfer request. The
1563 * response is provided with HTTP status code 1563 * response is provided with HTTP status code
1564 * #MHD_HTTP_INTERNAL_SERVER_ERROR. 1564 * #MHD_HTTP_INTERNAL_SERVER_ERROR.
1565 */ 1565 */
1566 TALER_EC_TRACK_TRANSFER_REQUEST_ERROR = 2403, 1566 TALER_EC_POST_TRANSFERS_REQUEST_ERROR = 2403,
1567 1567
1568 /** 1568 /**
1569 * We failed to persist wire transfer information in our merchant 1569 * We failed to persist wire transfer information in our merchant
1570 * database. The response is provided with HTTP status code 1570 * database. The response is provided with HTTP status code
1571 * #MHD_HTTP_INTERNAL_SERVER_ERROR. 1571 * #MHD_HTTP_INTERNAL_SERVER_ERROR.
1572 */ 1572 */
1573 TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR = 2404, 1573 TALER_EC_POST_TRANSFERS_DB_STORE_TRANSFER_ERROR = 2404,
1574 1574
1575 /** 1575 /**
1576 * The exchange returned an error from /track/transfer. The response 1576 * The exchange returned an error from /track/transfer. The response
1577 * is provided with HTTP status code #MHD_HTTP_FAILED_DEPENDENCY. 1577 * is provided with HTTP status code #MHD_HTTP_FAILED_DEPENDENCY.
1578 */ 1578 */
1579 TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR = 2405, 1579 TALER_EC_POST_TRANSFERS_EXCHANGE_ERROR = 2405,
1580 1580
1581 /** 1581 /**
1582 * We failed to fetch deposit information from our merchant database. 1582 * We failed to fetch deposit information from our merchant database.
1583 * The response is provided with HTTP status code 1583 * The response is provided with HTTP status code
1584 * #MHD_HTTP_INTERNAL_SERVER_ERROR. 1584 * #MHD_HTTP_INTERNAL_SERVER_ERROR.
1585 */ 1585 */
1586 TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR = 2406, 1586 TALER_EC_POST_TRANSFERS_DB_FETCH_DEPOSIT_ERROR = 2406,
1587 1587
1588 /** 1588 /**
1589 * We encountered an internal logic error. The response is provided 1589 * We encountered an internal logic error. The response is provided
1590 * with HTTP status code #MHD_HTTP_INTERNAL_SERVER_ERROR. 1590 * with HTTP status code #MHD_HTTP_INTERNAL_SERVER_ERROR.
1591 */ 1591 */
1592 TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR = 2407, 1592 TALER_EC_POST_TRANSFERS_DB_INTERNAL_LOGIC_ERROR = 2407,
1593 1593
1594 /** 1594 /**
1595 * The exchange gave conflicting information about a coin which has 1595 * The exchange gave conflicting information about a coin which has
1596 * been wire transferred. The response is provided with HTTP status 1596 * been wire transferred. The response is provided with HTTP status
1597 * code #MHD_HTTP_FAILED_DEPENDENCY. 1597 * code #MHD_HTTP_FAILED_DEPENDENCY.
1598 */ 1598 */
1599 TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS = 2408, 1599 TALER_EC_POST_TRANSFERS_CONFLICTING_REPORTS = 2408,
1600 1600
1601 /** 1601 /**
1602 * The merchant backend had problems in creating the JSON response. 1602 * The merchant backend had problems in creating the JSON response.
1603 */ 1603 */
1604 TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR = 2409, 1604 TALER_EC_POST_TRANSFERS_JSON_RESPONSE_ERROR = 2409,
1605 1605
1606 /** 1606 /**
1607 * The exchange charged a different wire fee than what it originally 1607 * The exchange charged a different wire fee than what it originally
1608 * advertised, and it is higher. The response is provied with an HTTP 1608 * advertised, and it is higher. The response is provided with an
1609 * status of #MHD_HTTP_FAILED_DEPENDENCY. 1609 * HTTP status of #MHD_HTTP_FAILED_DEPENDENCY.
1610 */ 1610 */
1611 TALER_EC_TRACK_TRANSFER_JSON_BAD_WIRE_FEE = 2410, 1611 TALER_EC_POST_TRANSFERS_JSON_BAD_WIRE_FEE = 2410,
1612
1613 /**
1614 * We did not find the account that the transfer was made to. The
1615 * response is provided with an HTTP status of #MHD_HTTP_NOT_FOUND.
1616 */
1617 TALER_EC_POST_TRANSFERS_ACCOUNT_NOT_FOUND = 2411,
1618
1619 /**
1620 * We did failed to store information in our database. The response is
1621 * provided with an HTTP status of #MHD_HTTP_INTERNAL_SERVER_ERROR.
1622 */
1623 TALER_EC_POST_TRANSFERS_DB_STORE_ERROR = 2412,
1624
1625 /**
1626 * We did failed to retrieve information from our database. The
1627 * response is provided with an HTTP status of
1628 * #MHD_HTTP_INTERNAL_SERVER_ERROR.
1629 */
1630 TALER_EC_POST_TRANSFERS_DB_LOOKUP_ERROR = 2413,
1612 1631
1613 /** 1632 /**
1614 * The merchant backend cannot create an instance under the given 1633 * The merchant backend cannot create an instance under the given
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 82b9b83df..38928dc18 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -756,6 +756,7 @@ struct TALER_EXCHANGE_DepositHandle;
756 * 756 *
757 * @param cls closure 757 * @param cls closure
758 * @param hr HTTP response data 758 * @param hr HTTP response data
759 * @param deposit_timestamp time when the exchange generated the deposit confirmation
759 * @param exchange_sig signature provided by the exchange 760 * @param exchange_sig signature provided by the exchange
760 * @param exchange_pub exchange key used to sign @a obj, or NULL 761 * @param exchange_pub exchange key used to sign @a obj, or NULL
761 */ 762 */
@@ -763,6 +764,7 @@ typedef void
763(*TALER_EXCHANGE_DepositResultCallback) ( 764(*TALER_EXCHANGE_DepositResultCallback) (
764 void *cls, 765 void *cls,
765 const struct TALER_EXCHANGE_HttpResponse *hr, 766 const struct TALER_EXCHANGE_HttpResponse *hr,
767 struct GNUNET_TIME_Absolute deposit_timestamp,
766 const struct TALER_ExchangeSignatureP *exchange_sig, 768 const struct TALER_ExchangeSignatureP *exchange_sig,
767 const struct TALER_ExchangePublicKeyP *exchange_pub); 769 const struct TALER_ExchangePublicKeyP *exchange_pub);
768 770
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 4fd580724..9fb932362 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -975,6 +975,8 @@ struct TALER_EXCHANGEDB_Session;
975 * @param cls closure 975 * @param cls closure
976 * @param rowid unique ID for the deposit in our DB, used for marking 976 * @param rowid unique ID for the deposit in our DB, used for marking
977 * it as 'tiny' or 'done' 977 * it as 'tiny' or 'done'
978 * @param exchange_timestamp when did the exchange receive the deposit
979 * @param wallet_timestamp when did the wallet sign the contract
978 * @param merchant_pub public key of the merchant 980 * @param merchant_pub public key of the merchant
979 * @param coin_pub public key of the coin 981 * @param coin_pub public key of the coin
980 * @param amount_with_fee amount that was deposited including fee 982 * @param amount_with_fee amount that was deposited including fee
@@ -990,6 +992,8 @@ typedef enum GNUNET_DB_QueryStatus
990(*TALER_EXCHANGEDB_DepositIterator)( 992(*TALER_EXCHANGEDB_DepositIterator)(
991 void *cls, 993 void *cls,
992 uint64_t rowid, 994 uint64_t rowid,
995 struct GNUNET_TIME_Absolute exchange_timestamp,
996 struct GNUNET_TIME_Absolute wallet_timestamp,
993 const struct TALER_MerchantPublicKeyP *merchant_pub, 997 const struct TALER_MerchantPublicKeyP *merchant_pub,
994 const struct TALER_CoinSpendPublicKeyP *coin_pub, 998 const struct TALER_CoinSpendPublicKeyP *coin_pub,
995 const struct TALER_Amount *amount_with_fee, 999 const struct TALER_Amount *amount_with_fee,
@@ -1022,7 +1026,8 @@ typedef void
1022 * 1026 *
1023 * @param cls closure 1027 * @param cls closure
1024 * @param rowid unique serial ID for the deposit in our DB 1028 * @param rowid unique serial ID for the deposit in our DB
1025 * @param timestamp when did the deposit happen 1029 * @param exchange_timestamp when did the deposit happen
1030 * @param wallet_timestamp when did the contract happen
1026 * @param merchant_pub public key of the merchant 1031 * @param merchant_pub public key of the merchant
1027 * @param denom_pub denomination public key of @a coin_pub 1032 * @param denom_pub denomination public key of @a coin_pub
1028 * @param coin_pub public key of the coin 1033 * @param coin_pub public key of the coin
@@ -1042,7 +1047,8 @@ typedef int
1042(*TALER_EXCHANGEDB_DepositCallback)( 1047(*TALER_EXCHANGEDB_DepositCallback)(
1043 void *cls, 1048 void *cls,
1044 uint64_t rowid, 1049 uint64_t rowid,
1045 struct GNUNET_TIME_Absolute timestamp, 1050 struct GNUNET_TIME_Absolute exchange_timestamp,
1051 struct GNUNET_TIME_Absolute wallet_timestamp,
1046 const struct TALER_MerchantPublicKeyP *merchant_pub, 1052 const struct TALER_MerchantPublicKeyP *merchant_pub,
1047 const struct TALER_DenominationPublicKey *denom_pub, 1053 const struct TALER_DenominationPublicKey *denom_pub,
1048 const struct TALER_CoinSpendPublicKeyP *coin_pub, 1054 const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -1841,6 +1847,8 @@ struct TALER_EXCHANGEDB_Plugin
1841 * @param session database connection 1847 * @param session database connection
1842 * @param deposit deposit to search for 1848 * @param deposit deposit to search for
1843 * @param check_extras whether to check extra fields or not 1849 * @param check_extras whether to check extra fields or not
1850 * @param[out] deposit_fee set to the deposit fee the exchange charged
1851 * @param[out] exchange_timestamp set to the time when the exchange received the deposit
1844 * @return 1 if we know this operation, 1852 * @return 1 if we know this operation,
1845 * 0 if this exact deposit is unknown to us, 1853 * 0 if this exact deposit is unknown to us,
1846 * otherwise transaction error status 1854 * otherwise transaction error status
@@ -1849,7 +1857,9 @@ struct TALER_EXCHANGEDB_Plugin
1849 (*have_deposit)(void *cls, 1857 (*have_deposit)(void *cls,
1850 struct TALER_EXCHANGEDB_Session *session, 1858 struct TALER_EXCHANGEDB_Session *session,
1851 const struct TALER_EXCHANGEDB_Deposit *deposit, 1859 const struct TALER_EXCHANGEDB_Deposit *deposit,
1852 int check_extras); 1860 int check_extras,
1861 struct TALER_Amount *deposit_fee,
1862 struct GNUNET_TIME_Absolute *exchange_timestamp);
1853 1863
1854 1864
1855 /** 1865 /**
@@ -1857,12 +1867,14 @@ struct TALER_EXCHANGEDB_Plugin
1857 * 1867 *
1858 * @param cls the @e cls of this struct with the plugin-specific state 1868 * @param cls the @e cls of this struct with the plugin-specific state
1859 * @param session connection to the database 1869 * @param session connection to the database
1870 * @param exchange_timestamp time the exchange received the deposit request
1860 * @param deposit deposit information to store 1871 * @param deposit deposit information to store
1861 * @return query result status 1872 * @return query result status
1862 */ 1873 */
1863 enum GNUNET_DB_QueryStatus 1874 enum GNUNET_DB_QueryStatus
1864 (*insert_deposit)(void *cls, 1875 (*insert_deposit)(void *cls,
1865 struct TALER_EXCHANGEDB_Session *session, 1876 struct TALER_EXCHANGEDB_Session *session,
1877 struct GNUNET_TIME_Absolute exchange_timestamp,
1866 const struct TALER_EXCHANGEDB_Deposit *deposit); 1878 const struct TALER_EXCHANGEDB_Deposit *deposit);
1867 1879
1868 1880
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index c346a6cee..38b895d7f 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -363,7 +363,7 @@ struct TALER_DepositRequestPS
363 * deposit request in a timely fashion (so back-dating is not 363 * deposit request in a timely fashion (so back-dating is not
364 * prevented). 364 * prevented).
365 */ 365 */
366 struct GNUNET_TIME_AbsoluteNBO timestamp; 366 struct GNUNET_TIME_AbsoluteNBO wallet_timestamp;
367 367
368 /** 368 /**
369 * How much time does the merchant have to issue a refund request? 369 * How much time does the merchant have to issue a refund request?
@@ -429,9 +429,10 @@ struct TALER_DepositConfirmationPS
429 struct GNUNET_HashCode h_wire GNUNET_PACKED; 429 struct GNUNET_HashCode h_wire GNUNET_PACKED;
430 430
431 /** 431 /**
432 * Time when this confirmation was generated. 432 * Time when this confirmation was generated / when the exchange received
433 * the deposit request.
433 */ 434 */
434 struct GNUNET_TIME_AbsoluteNBO timestamp; 435 struct GNUNET_TIME_AbsoluteNBO exchange_timestamp;
435 436
436 /** 437 /**
437 * How much time does the @e merchant have to issue a refund 438 * How much time does the @e merchant have to issue a refund
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index acc218ac5..6a4fa024a 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -1903,6 +1903,7 @@ TALER_TESTING_cmd_connect_with_state (const char *label,
1903 * @param dbc collects plugin and session handles 1903 * @param dbc collects plugin and session handles
1904 * @param merchant_name Human-readable name of the merchant. 1904 * @param merchant_name Human-readable name of the merchant.
1905 * @param merchant_account merchant's account name (NOT a payto:// URI) 1905 * @param merchant_account merchant's account name (NOT a payto:// URI)
1906 * @param exchange_timestamp when did the exchange receive the deposit
1906 * @param wire_deadline point in time where the aggregator should have 1907 * @param wire_deadline point in time where the aggregator should have
1907 * wired money to the merchant. 1908 * wired money to the merchant.
1908 * @param amount_with_fee amount to deposit (inclusive of deposit fee) 1909 * @param amount_with_fee amount to deposit (inclusive of deposit fee)
@@ -1910,14 +1911,15 @@ TALER_TESTING_cmd_connect_with_state (const char *label,
1910 * @return the command. 1911 * @return the command.
1911 */ 1912 */
1912struct TALER_TESTING_Command 1913struct TALER_TESTING_Command
1913TALER_TESTING_cmd_insert_deposit (const char *label, 1914TALER_TESTING_cmd_insert_deposit (
1914 const struct 1915 const char *label,
1915 TALER_TESTING_DatabaseConnection *dbc, 1916 const struct TALER_TESTING_DatabaseConnection *dbc,
1916 const char *merchant_name, 1917 const char *merchant_name,
1917 const char *merchant_account, 1918 const char *merchant_account,
1918 struct GNUNET_TIME_Relative wire_deadline, 1919 struct GNUNET_TIME_Absolute exchange_timestamp,
1919 const char *amount_with_fee, 1920 struct GNUNET_TIME_Relative wire_deadline,
1920 const char *deposit_fee); 1921 const char *amount_with_fee,
1922 const char *deposit_fee);
1921 1923
1922 1924
1923/** 1925/**
diff --git a/src/lib/auditor_api_deposit_confirmation.c b/src/lib/auditor_api_deposit_confirmation.c
index cddfe8b14..1856a89f4 100644
--- a/src/lib/auditor_api_deposit_confirmation.c
+++ b/src/lib/auditor_api_deposit_confirmation.c
@@ -148,7 +148,7 @@ handle_deposit_confirmation_finished (void *cls,
148 * 148 *
149 * @param h_wire hash of merchant wire details 149 * @param h_wire hash of merchant wire details
150 * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor) 150 * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor)
151 * @param timestamp timestamp when the contract was finalized, must not be too far in the future 151 * @param exchange_timestamp timestamp when the deposit was received by the wallet
152 * @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline 152 * @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline
153 * @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant 153 * @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant
154 * @param coin_pub coin’s public key 154 * @param coin_pub coin’s public key
@@ -165,7 +165,7 @@ handle_deposit_confirmation_finished (void *cls,
165static int 165static int
166verify_signatures (const struct GNUNET_HashCode *h_wire, 166verify_signatures (const struct GNUNET_HashCode *h_wire,
167 const struct GNUNET_HashCode *h_contract_terms, 167 const struct GNUNET_HashCode *h_contract_terms,
168 struct GNUNET_TIME_Absolute timestamp, 168 struct GNUNET_TIME_Absolute exchange_timestamp,
169 struct GNUNET_TIME_Absolute refund_deadline, 169 struct GNUNET_TIME_Absolute refund_deadline,
170 const struct TALER_Amount *amount_without_fee, 170 const struct TALER_Amount *amount_without_fee,
171 const struct TALER_CoinSpendPublicKeyP *coin_pub, 171 const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -184,7 +184,7 @@ verify_signatures (const struct GNUNET_HashCode *h_wire,
184 .purpose.size = htonl (sizeof (dc)), 184 .purpose.size = htonl (sizeof (dc)),
185 .h_contract_terms = *h_contract_terms, 185 .h_contract_terms = *h_contract_terms,
186 .h_wire = *h_wire, 186 .h_wire = *h_wire,
187 .timestamp = GNUNET_TIME_absolute_hton (timestamp), 187 .exchange_timestamp = GNUNET_TIME_absolute_hton (exchange_timestamp),
188 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline), 188 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
189 .coin_pub = *coin_pub, 189 .coin_pub = *coin_pub,
190 .merchant = *merchant_pub 190 .merchant = *merchant_pub
@@ -256,7 +256,7 @@ verify_signatures (const struct GNUNET_HashCode *h_wire,
256 * @param auditor the auditor handle; the auditor must be ready to operate 256 * @param auditor the auditor handle; the auditor must be ready to operate
257 * @param h_wire hash of merchant wire details 257 * @param h_wire hash of merchant wire details
258 * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor) 258 * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor)
259 * @param timestamp timestamp when the contract was finalized, must not be too far in the future 259 * @param exchange_timestamp timestamp when deposit was received by the exchange
260 * @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline 260 * @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline
261 * @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant 261 * @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant
262 * @param coin_pub coin’s public key 262 * @param coin_pub coin’s public key
@@ -278,7 +278,7 @@ TALER_AUDITOR_deposit_confirmation (
278 struct TALER_AUDITOR_Handle *auditor, 278 struct TALER_AUDITOR_Handle *auditor,
279 const struct GNUNET_HashCode *h_wire, 279 const struct GNUNET_HashCode *h_wire,
280 const struct GNUNET_HashCode *h_contract_terms, 280 const struct GNUNET_HashCode *h_contract_terms,
281 struct GNUNET_TIME_Absolute timestamp, 281 struct GNUNET_TIME_Absolute exchange_timestamp,
282 struct GNUNET_TIME_Absolute refund_deadline, 282 struct GNUNET_TIME_Absolute refund_deadline,
283 const struct TALER_Amount *amount_without_fee, 283 const struct TALER_Amount *amount_without_fee,
284 const struct TALER_CoinSpendPublicKeyP *coin_pub, 284 const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -298,7 +298,7 @@ TALER_AUDITOR_deposit_confirmation (
298 json_t *deposit_confirmation_obj; 298 json_t *deposit_confirmation_obj;
299 CURL *eh; 299 CURL *eh;
300 300
301 (void) GNUNET_TIME_round_abs (&timestamp); 301 (void) GNUNET_TIME_round_abs (&exchange_timestamp);
302 (void) GNUNET_TIME_round_abs (&refund_deadline); 302 (void) GNUNET_TIME_round_abs (&refund_deadline);
303 (void) GNUNET_TIME_round_abs (&ep_start); 303 (void) GNUNET_TIME_round_abs (&ep_start);
304 (void) GNUNET_TIME_round_abs (&ep_expire); 304 (void) GNUNET_TIME_round_abs (&ep_expire);
@@ -308,7 +308,7 @@ TALER_AUDITOR_deposit_confirmation (
308 if (GNUNET_OK != 308 if (GNUNET_OK !=
309 verify_signatures (h_wire, 309 verify_signatures (h_wire,
310 h_contract_terms, 310 h_contract_terms,
311 timestamp, 311 exchange_timestamp,
312 refund_deadline, 312 refund_deadline,
313 amount_without_fee, 313 amount_without_fee,
314 coin_pub, 314 coin_pub,
@@ -336,7 +336,8 @@ TALER_AUDITOR_deposit_confirmation (
336 "h_wire", GNUNET_JSON_from_data_auto (h_wire), 336 "h_wire", GNUNET_JSON_from_data_auto (h_wire),
337 "h_contract_terms", GNUNET_JSON_from_data_auto ( 337 "h_contract_terms", GNUNET_JSON_from_data_auto (
338 h_contract_terms), 338 h_contract_terms),
339 "timestamp", GNUNET_JSON_from_time_abs (timestamp), 339 "exchange_timestamp", GNUNET_JSON_from_time_abs (
340 exchange_timestamp),
340 "refund_deadline", GNUNET_JSON_from_time_abs (refund_deadline), 341 "refund_deadline", GNUNET_JSON_from_time_abs (refund_deadline),
341 "amount_without_fee", TALER_JSON_from_amount ( 342 "amount_without_fee", TALER_JSON_from_amount (
342 amount_without_fee), 343 amount_without_fee),
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index dc44291d0..bf8eb5376 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -524,7 +524,7 @@ TALER_EXCHANGE_verify_coin_history (
524 GNUNET_JSON_spec_fixed_auto ("h_wire", 524 GNUNET_JSON_spec_fixed_auto ("h_wire",
525 &dr.h_wire), 525 &dr.h_wire),
526 GNUNET_JSON_spec_absolute_time_nbo ("timestamp", 526 GNUNET_JSON_spec_absolute_time_nbo ("timestamp",
527 &dr.timestamp), 527 &dr.wallet_timestamp),
528 GNUNET_JSON_spec_absolute_time_nbo ("refund_deadline", 528 GNUNET_JSON_spec_absolute_time_nbo ("refund_deadline",
529 &dr.refund_deadline), 529 &dr.refund_deadline),
530 TALER_JSON_spec_amount_nbo ("deposit_fee", 530 TALER_JSON_spec_amount_nbo ("deposit_fee",
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index a5cf6c36a..276053658 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -160,7 +160,7 @@ auditor_cb (void *cls,
160 ah, 160 ah,
161 &dh->depconf.h_wire, 161 &dh->depconf.h_wire,
162 &dh->depconf.h_contract_terms, 162 &dh->depconf.h_contract_terms,
163 GNUNET_TIME_absolute_ntoh (dh->depconf.timestamp), 163 GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp),
164 GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline), 164 GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline),
165 &amount_without_fee, 165 &amount_without_fee,
166 &dh->depconf.coin_pub, 166 &dh->depconf.coin_pub,
@@ -198,6 +198,8 @@ verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
198 struct GNUNET_JSON_Specification spec[] = { 198 struct GNUNET_JSON_Specification spec[] = {
199 GNUNET_JSON_spec_fixed_auto ("exchange_sig", exchange_sig), 199 GNUNET_JSON_spec_fixed_auto ("exchange_sig", exchange_sig),
200 GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub), 200 GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
201 GNUNET_JSON_spec_absolute_time_nbo ("exchange_timestamp",
202 &dh->depconf.exchange_timestamp),
201 GNUNET_JSON_spec_end () 203 GNUNET_JSON_spec_end ()
202 }; 204 };
203 205
@@ -386,6 +388,7 @@ handle_deposit_finished (void *cls,
386 } 388 }
387 dh->cb (dh->cb_cls, 389 dh->cb (dh->cb_cls,
388 &hr, 390 &hr,
391 GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp),
389 es, 392 es,
390 ep); 393 ep);
391 TALER_EXCHANGE_deposit_cancel (dh); 394 TALER_EXCHANGE_deposit_cancel (dh);
@@ -429,7 +432,7 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
429 .purpose.size = htonl (sizeof (dr)), 432 .purpose.size = htonl (sizeof (dr)),
430 .h_contract_terms = *h_contract_terms, 433 .h_contract_terms = *h_contract_terms,
431 .h_wire = *h_wire, 434 .h_wire = *h_wire,
432 .timestamp = GNUNET_TIME_absolute_hton (timestamp), 435 .wallet_timestamp = GNUNET_TIME_absolute_hton (timestamp),
433 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline), 436 .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
434 .merchant = *merchant_pub, 437 .merchant = *merchant_pub,
435 .coin_pub = *coin_pub 438 .coin_pub = *coin_pub
@@ -658,7 +661,7 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
658 TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT); 661 TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT);
659 dh->depconf.h_contract_terms = *h_contract_terms; 662 dh->depconf.h_contract_terms = *h_contract_terms;
660 dh->depconf.h_wire = h_wire; 663 dh->depconf.h_wire = h_wire;
661 dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp); 664 /* dh->depconf.exchange_timestamp; -- initialized later from exchange reply! */
662 dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); 665 dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
663 TALER_amount_hton (&dh->depconf.amount_without_fee, 666 TALER_amount_hton (&dh->depconf.amount_without_fee,
664 &amount_without_fee); 667 &amount_without_fee);
diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c
index b1ea176bf..6f91389f1 100644
--- a/src/lib/exchange_api_refund.c
+++ b/src/lib/exchange_api_refund.c
@@ -148,7 +148,8 @@ handle_refund_finished (void *cls,
148 struct TALER_ExchangeSignatureP exchange_sig; 148 struct TALER_ExchangeSignatureP exchange_sig;
149 struct TALER_ExchangePublicKeyP *ep = NULL; 149 struct TALER_ExchangePublicKeyP *ep = NULL;
150 struct TALER_ExchangeSignatureP *es = NULL; 150 struct TALER_ExchangeSignatureP *es = NULL;
151 struct TALER_Amount *rf = NULL; 151 struct TALER_Amount ra;
152 const struct TALER_Amount *rf = NULL;
152 const json_t *j = response; 153 const json_t *j = response;
153 struct TALER_EXCHANGE_HttpResponse hr = { 154 struct TALER_EXCHANGE_HttpResponse hr = {
154 .reply = j, 155 .reply = j,
@@ -176,7 +177,9 @@ handle_refund_finished (void *cls,
176 { 177 {
177 ep = &exchange_pub; 178 ep = &exchange_pub;
178 es = &exchange_sig; 179 es = &exchange_sig;
179 rf = &rh->depconf.refund_fee; 180 TALER_amount_ntoh (&ra,
181 &rh->depconf.refund_fee);
182 rf = &ra;
180 } 183 }
181 break; 184 break;
182 case MHD_HTTP_BAD_REQUEST: 185 case MHD_HTTP_BAD_REQUEST:
diff --git a/src/testing/test_taler_exchange_aggregator.c b/src/testing/test_taler_exchange_aggregator.c
index eaa621cfe..d5c392d3a 100644
--- a/src/testing/test_taler_exchange_aggregator.c
+++ b/src/testing/test_taler_exchange_aggregator.c
@@ -108,6 +108,7 @@ run (void *cls,
108 &dbc, 108 &dbc,
109 "bob", 109 "bob",
110 USER42_ACCOUNT, 110 USER42_ACCOUNT,
111 GNUNET_TIME_absolute_get (),
111 GNUNET_TIME_UNIT_ZERO, 112 GNUNET_TIME_UNIT_ZERO,
112 "EUR:1", 113 "EUR:1",
113 "EUR:0.1"), 114 "EUR:0.1"),
@@ -126,6 +127,7 @@ run (void *cls,
126 &dbc, 127 &dbc,
127 "bob", 128 "bob",
128 USER42_ACCOUNT, 129 USER42_ACCOUNT,
130 GNUNET_TIME_absolute_get (),
129 GNUNET_TIME_UNIT_ZERO, 131 GNUNET_TIME_UNIT_ZERO,
130 "EUR:1", 132 "EUR:1",
131 "EUR:0.1"), 133 "EUR:0.1"),
@@ -134,6 +136,7 @@ run (void *cls,
134 &dbc, 136 &dbc,
135 "bob", 137 "bob",
136 USER42_ACCOUNT, 138 USER42_ACCOUNT,
139 GNUNET_TIME_absolute_get (),
137 GNUNET_TIME_UNIT_ZERO, 140 GNUNET_TIME_UNIT_ZERO,
138 "EUR:1", 141 "EUR:1",
139 "EUR:0.1"), 142 "EUR:0.1"),
@@ -153,6 +156,7 @@ run (void *cls,
153 &dbc, 156 &dbc,
154 "bob", 157 "bob",
155 "4", 158 "4",
159 GNUNET_TIME_absolute_get (),
156 GNUNET_TIME_UNIT_ZERO, 160 GNUNET_TIME_UNIT_ZERO,
157 "EUR:1", 161 "EUR:1",
158 "EUR:0.1"), 162 "EUR:0.1"),
@@ -160,6 +164,7 @@ run (void *cls,
160 &dbc, 164 &dbc,
161 "bob", 165 "bob",
162 "5", 166 "5",
167 GNUNET_TIME_absolute_get (),
163 GNUNET_TIME_UNIT_ZERO, 168 GNUNET_TIME_UNIT_ZERO,
164 "EUR:1", 169 "EUR:1",
165 "EUR:0.1"), 170 "EUR:0.1"),
@@ -167,6 +172,7 @@ run (void *cls,
167 &dbc, 172 &dbc,
168 "alice", 173 "alice",
169 "4", 174 "4",
175 GNUNET_TIME_absolute_get (),
170 GNUNET_TIME_UNIT_ZERO, 176 GNUNET_TIME_UNIT_ZERO,
171 "EUR:1", 177 "EUR:1",
172 "EUR:0.1"), 178 "EUR:0.1"),
@@ -195,6 +201,7 @@ run (void *cls,
195 &dbc, 201 &dbc,
196 "bob", 202 "bob",
197 USER42_ACCOUNT, 203 USER42_ACCOUNT,
204 GNUNET_TIME_absolute_get (),
198 GNUNET_TIME_relative_multiply 205 GNUNET_TIME_relative_multiply
199 (GNUNET_TIME_UNIT_SECONDS, 206 (GNUNET_TIME_UNIT_SECONDS,
200 5), 207 5),
@@ -204,6 +211,7 @@ run (void *cls,
204 &dbc, 211 &dbc,
205 "bob", 212 "bob",
206 USER42_ACCOUNT, 213 USER42_ACCOUNT,
214 GNUNET_TIME_absolute_get (),
207 GNUNET_TIME_relative_multiply 215 GNUNET_TIME_relative_multiply
208 (GNUNET_TIME_UNIT_SECONDS, 216 (GNUNET_TIME_UNIT_SECONDS,
209 5), 217 5),
@@ -229,6 +237,7 @@ run (void *cls,
229 &dbc, 237 &dbc,
230 "bob", 238 "bob",
231 USER42_ACCOUNT, 239 USER42_ACCOUNT,
240 GNUNET_TIME_absolute_get (),
232 GNUNET_TIME_relative_multiply 241 GNUNET_TIME_relative_multiply
233 (GNUNET_TIME_UNIT_SECONDS, 242 (GNUNET_TIME_UNIT_SECONDS,
234 10), 243 10),
@@ -239,6 +248,7 @@ run (void *cls,
239 &dbc, 248 &dbc,
240 "bob", 249 "bob",
241 USER42_ACCOUNT, 250 USER42_ACCOUNT,
251 GNUNET_TIME_absolute_get (),
242 GNUNET_TIME_relative_multiply 252 GNUNET_TIME_relative_multiply
243 (GNUNET_TIME_UNIT_SECONDS, 253 (GNUNET_TIME_UNIT_SECONDS,
244 5), 254 5),
@@ -263,6 +273,7 @@ run (void *cls,
263 &dbc, 273 &dbc,
264 "bob", 274 "bob",
265 USER42_ACCOUNT, 275 USER42_ACCOUNT,
276 GNUNET_TIME_absolute_get (),
266 GNUNET_TIME_UNIT_ZERO, 277 GNUNET_TIME_UNIT_ZERO,
267 "EUR:0.102", 278 "EUR:0.102",
268 "EUR:0.1"), 279 "EUR:0.1"),
@@ -274,6 +285,7 @@ run (void *cls,
274 &dbc, 285 &dbc,
275 "bob", 286 "bob",
276 USER42_ACCOUNT, 287 USER42_ACCOUNT,
288 GNUNET_TIME_absolute_get (),
277 GNUNET_TIME_UNIT_ZERO, 289 GNUNET_TIME_UNIT_ZERO,
278 "EUR:0.102", 290 "EUR:0.102",
279 "EUR:0.1"), 291 "EUR:0.1"),
@@ -281,6 +293,7 @@ run (void *cls,
281 &dbc, 293 &dbc,
282 "bob", 294 "bob",
283 USER42_ACCOUNT, 295 USER42_ACCOUNT,
296 GNUNET_TIME_absolute_get (),
284 GNUNET_TIME_UNIT_ZERO, 297 GNUNET_TIME_UNIT_ZERO,
285 "EUR:0.102", 298 "EUR:0.102",
286 "EUR:0.1"), 299 "EUR:0.1"),
@@ -292,6 +305,7 @@ run (void *cls,
292 &dbc, 305 &dbc,
293 "bob", 306 "bob",
294 USER42_ACCOUNT, 307 USER42_ACCOUNT,
308 GNUNET_TIME_absolute_get (),
295 GNUNET_TIME_UNIT_ZERO, 309 GNUNET_TIME_UNIT_ZERO,
296 "EUR:0.102", 310 "EUR:0.102",
297 "EUR:0.1"), 311 "EUR:0.1"),
@@ -303,6 +317,7 @@ run (void *cls,
303 &dbc, 317 &dbc,
304 "bob", 318 "bob",
305 USER42_ACCOUNT, 319 USER42_ACCOUNT,
320 GNUNET_TIME_absolute_get (),
306 GNUNET_TIME_UNIT_ZERO, 321 GNUNET_TIME_UNIT_ZERO,
307 "EUR:0.112", 322 "EUR:0.112",
308 "EUR:0.1"), 323 "EUR:0.1"),
@@ -319,6 +334,7 @@ run (void *cls,
319 &dbc, 334 &dbc,
320 "bob", 335 "bob",
321 USER42_ACCOUNT, 336 USER42_ACCOUNT,
337 GNUNET_TIME_absolute_get (),
322 GNUNET_TIME_UNIT_ZERO, 338 GNUNET_TIME_UNIT_ZERO,
323 "EUR:0.109", 339 "EUR:0.109",
324 "EUR:0.1"), 340 "EUR:0.1"),
@@ -330,6 +346,7 @@ run (void *cls,
330 &dbc, 346 &dbc,
331 "bob", 347 "bob",
332 USER42_ACCOUNT, 348 USER42_ACCOUNT,
349 GNUNET_TIME_absolute_get (),
333 GNUNET_TIME_UNIT_ZERO, 350 GNUNET_TIME_UNIT_ZERO,
334 "EUR:0.119", 351 "EUR:0.119",
335 "EUR:0.1"), 352 "EUR:0.1"),
@@ -346,6 +363,7 @@ run (void *cls,
346 &dbc, 363 &dbc,
347 "bob", 364 "bob",
348 USER42_ACCOUNT, 365 USER42_ACCOUNT,
366 GNUNET_TIME_absolute_get (),
349 GNUNET_TIME_UNIT_ZERO, 367 GNUNET_TIME_UNIT_ZERO,
350 "EUR:0.122", 368 "EUR:0.122",
351 "EUR:0.1"), 369 "EUR:0.1"),
@@ -362,6 +380,7 @@ run (void *cls,
362 &dbc, 380 &dbc,
363 "bob", 381 "bob",
364 USER42_ACCOUNT, 382 USER42_ACCOUNT,
383 GNUNET_TIME_absolute_get (),
365 GNUNET_TIME_relative_multiply 384 GNUNET_TIME_relative_multiply
366 (GNUNET_TIME_UNIT_SECONDS, 385 (GNUNET_TIME_UNIT_SECONDS,
367 5), 386 5),
@@ -375,6 +394,7 @@ run (void *cls,
375 &dbc, 394 &dbc,
376 "bob", 395 "bob",
377 USER42_ACCOUNT, 396 USER42_ACCOUNT,
397 GNUNET_TIME_absolute_get (),
378 GNUNET_TIME_relative_multiply 398 GNUNET_TIME_relative_multiply
379 (GNUNET_TIME_UNIT_SECONDS, 399 (GNUNET_TIME_UNIT_SECONDS,
380 5), 400 5),
@@ -390,6 +410,7 @@ run (void *cls,
390 &dbc, 410 &dbc,
391 "bob", 411 "bob",
392 USER42_ACCOUNT, 412 USER42_ACCOUNT,
413 GNUNET_TIME_absolute_get (),
393 GNUNET_TIME_UNIT_ZERO, 414 GNUNET_TIME_UNIT_ZERO,
394 "EUR:0.122", 415 "EUR:0.122",
395 "EUR:0.1"), 416 "EUR:0.1"),
@@ -406,6 +427,7 @@ run (void *cls,
406 &dbc, 427 &dbc,
407 "bob", 428 "bob",
408 USER42_ACCOUNT, 429 USER42_ACCOUNT,
430 GNUNET_TIME_absolute_get (),
409 GNUNET_TIME_relative_multiply 431 GNUNET_TIME_relative_multiply
410 (GNUNET_TIME_UNIT_SECONDS, 432 (GNUNET_TIME_UNIT_SECONDS,
411 5), 433 5),
@@ -419,6 +441,7 @@ run (void *cls,
419 &dbc, 441 &dbc,
420 "bob", 442 "bob",
421 USER42_ACCOUNT, 443 USER42_ACCOUNT,
444 GNUNET_TIME_absolute_get (),
422 GNUNET_TIME_relative_multiply 445 GNUNET_TIME_relative_multiply
423 (GNUNET_TIME_UNIT_SECONDS, 446 (GNUNET_TIME_UNIT_SECONDS,
424 5), 447 5),
@@ -434,6 +457,7 @@ run (void *cls,
434 &dbc, 457 &dbc,
435 "bob", 458 "bob",
436 USER42_ACCOUNT, 459 USER42_ACCOUNT,
460 GNUNET_TIME_absolute_get (),
437 GNUNET_TIME_UNIT_ZERO, 461 GNUNET_TIME_UNIT_ZERO,
438 "EUR:0.112", 462 "EUR:0.112",
439 "EUR:0.1"), 463 "EUR:0.1"),
diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
index 247399a9d..1442380bf 100644
--- a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
+++ b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
@@ -203,6 +203,7 @@ deposit_confirmation_run (void *cls,
203 const struct TALER_TESTING_Command *deposit_cmd; 203 const struct TALER_TESTING_Command *deposit_cmd;
204 struct GNUNET_HashCode h_wire; 204 struct GNUNET_HashCode h_wire;
205 struct GNUNET_HashCode h_contract_terms; 205 struct GNUNET_HashCode h_contract_terms;
206 const struct GNUNET_TIME_Absolute *exchange_timestamp = NULL;
206 struct GNUNET_TIME_Absolute timestamp; 207 struct GNUNET_TIME_Absolute timestamp;
207 struct GNUNET_TIME_Absolute refund_deadline; 208 struct GNUNET_TIME_Absolute refund_deadline;
208 struct TALER_Amount amount_without_fee; 209 struct TALER_Amount amount_without_fee;
@@ -238,6 +239,11 @@ deposit_confirmation_run (void *cls,
238 TALER_TESTING_get_trait_exchange_sig (deposit_cmd, 239 TALER_TESTING_get_trait_exchange_sig (deposit_cmd,
239 dcs->coin_index, 240 dcs->coin_index,
240 &exchange_sig)); 241 &exchange_sig));
242 GNUNET_assert (GNUNET_OK ==
243 TALER_TESTING_get_trait_absolute_time (deposit_cmd,
244 dcs->coin_index,
245 &exchange_timestamp));
246 GNUNET_assert (NULL != exchange_timestamp);
241 keys = TALER_EXCHANGE_get_keys (dcs->is->exchange); 247 keys = TALER_EXCHANGE_get_keys (dcs->is->exchange);
242 GNUNET_assert (NULL != keys); 248 GNUNET_assert (NULL != keys);
243 spk = TALER_EXCHANGE_get_signing_key_info (keys, 249 spk = TALER_EXCHANGE_get_signing_key_info (keys,
@@ -309,7 +315,7 @@ deposit_confirmation_run (void *cls,
309 dcs->dc = TALER_AUDITOR_deposit_confirmation (dcs->auditor, 315 dcs->dc = TALER_AUDITOR_deposit_confirmation (dcs->auditor,
310 &h_wire, 316 &h_wire,
311 &h_contract_terms, 317 &h_contract_terms,
312 timestamp, 318 *exchange_timestamp,
313 refund_deadline, 319 refund_deadline,
314 &amount_without_fee, 320 &amount_without_fee,
315 &coin_pub, 321 &coin_pub,
diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c
index 9468e7acb..049f36f25 100644
--- a/src/testing/testing_api_cmd_deposit.c
+++ b/src/testing/testing_api_cmd_deposit.c
@@ -91,9 +91,9 @@ struct DepositState
91 struct TALER_EXCHANGE_DepositHandle *dh; 91 struct TALER_EXCHANGE_DepositHandle *dh;
92 92
93 /** 93 /**
94 * Timestamp of the /deposit operation. 94 * Timestamp of the /deposit operation in the wallet (contract signing time).
95 */ 95 */
96 struct GNUNET_TIME_Absolute timestamp; 96 struct GNUNET_TIME_Absolute wallet_timestamp;
97 97
98 /** 98 /**
99 * Interpreter state. 99 * Interpreter state.
@@ -127,6 +127,11 @@ struct DepositState
127 int deposit_succeeded; 127 int deposit_succeeded;
128 128
129 /** 129 /**
130 * When did the exchange receive the deposit?
131 */
132 struct GNUNET_TIME_Absolute exchange_timestamp;
133
134 /**
130 * Signing key used by the exchange to sign the 135 * Signing key used by the exchange to sign the
131 * deposit confirmation. 136 * deposit confirmation.
132 */ 137 */
@@ -198,6 +203,7 @@ do_retry (void *cls)
198 * 203 *
199 * @param cls closure. 204 * @param cls closure.
200 * @param hr HTTP response details 205 * @param hr HTTP response details
206 * @param exchange_timestamp when did the exchange receive the deposit permission
201 * @param exchange_sig signature provided by the exchange 207 * @param exchange_sig signature provided by the exchange
202 * (NULL on errors) 208 * (NULL on errors)
203 * @param exchange_pub public key of the exchange, 209 * @param exchange_pub public key of the exchange,
@@ -206,6 +212,7 @@ do_retry (void *cls)
206static void 212static void
207deposit_cb (void *cls, 213deposit_cb (void *cls,
208 const struct TALER_EXCHANGE_HttpResponse *hr, 214 const struct TALER_EXCHANGE_HttpResponse *hr,
215 const struct GNUNET_TIME_Absolute exchange_timestamp,
209 const struct TALER_ExchangeSignatureP *exchange_sig, 216 const struct TALER_ExchangeSignatureP *exchange_sig,
210 const struct TALER_ExchangePublicKeyP *exchange_pub) 217 const struct TALER_ExchangePublicKeyP *exchange_pub)
211{ 218{
@@ -254,6 +261,7 @@ deposit_cb (void *cls,
254 if (MHD_HTTP_OK == hr->http_status) 261 if (MHD_HTTP_OK == hr->http_status)
255 { 262 {
256 ds->deposit_succeeded = GNUNET_YES; 263 ds->deposit_succeeded = GNUNET_YES;
264 ds->exchange_timestamp = exchange_timestamp;
257 ds->exchange_pub = *exchange_pub; 265 ds->exchange_pub = *exchange_pub;
258 ds->exchange_sig = *exchange_sig; 266 ds->exchange_sig = *exchange_sig;
259 } 267 }
@@ -305,7 +313,7 @@ deposit_run (void *cls,
305 ds->coin_index = ods->coin_index; 313 ds->coin_index = ods->coin_index;
306 ds->wire_details = json_incref (ods->wire_details); 314 ds->wire_details = json_incref (ods->wire_details);
307 ds->contract_terms = json_incref (ods->contract_terms); 315 ds->contract_terms = json_incref (ods->contract_terms);
308 ds->timestamp = ods->timestamp; 316 ds->wallet_timestamp = ods->wallet_timestamp;
309 ds->refund_deadline = ods->refund_deadline; 317 ds->refund_deadline = ods->refund_deadline;
310 ds->amount = ods->amount; 318 ds->amount = ods->amount;
311 ds->merchant_priv = ods->merchant_priv; 319 ds->merchant_priv = ods->merchant_priv;
@@ -379,7 +387,7 @@ deposit_run (void *cls,
379 } 387 }
380 else 388 else
381 { 389 {
382 ds->refund_deadline = ds->timestamp; 390 ds->refund_deadline = ds->wallet_timestamp;
383 wire_deadline = GNUNET_TIME_relative_to_absolute 391 wire_deadline = GNUNET_TIME_relative_to_absolute
384 (GNUNET_TIME_UNIT_ZERO); 392 (GNUNET_TIME_UNIT_ZERO);
385 } 393 }
@@ -388,6 +396,7 @@ deposit_run (void *cls,
388 396
389 (void) GNUNET_TIME_round_abs (&wire_deadline); 397 (void) GNUNET_TIME_round_abs (&wire_deadline);
390 398
399 // FIXME: This should be part of TALER_EXCHANGE_deposit()!
391 { 400 {
392 struct TALER_DepositRequestPS dr; 401 struct TALER_DepositRequestPS dr;
393 402
@@ -400,7 +409,7 @@ deposit_run (void *cls,
400 GNUNET_assert (GNUNET_OK == 409 GNUNET_assert (GNUNET_OK ==
401 TALER_JSON_merchant_wire_signature_hash (ds->wire_details, 410 TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
402 &dr.h_wire)); 411 &dr.h_wire));
403 dr.timestamp = GNUNET_TIME_absolute_hton (ds->timestamp); 412 dr.wallet_timestamp = GNUNET_TIME_absolute_hton (ds->wallet_timestamp);
404 dr.refund_deadline = GNUNET_TIME_absolute_hton 413 dr.refund_deadline = GNUNET_TIME_absolute_hton
405 (ds->refund_deadline); 414 (ds->refund_deadline);
406 TALER_amount_hton (&dr.amount_with_fee, 415 TALER_amount_hton (&dr.amount_with_fee,
@@ -421,7 +430,7 @@ deposit_run (void *cls,
421 &coin_pub, 430 &coin_pub,
422 denom_pub_sig, 431 denom_pub_sig,
423 &denom_pub->key, 432 &denom_pub->key,
424 ds->timestamp, 433 ds->wallet_timestamp,
425 &merchant_pub, 434 &merchant_pub,
426 ds->refund_deadline, 435 ds->refund_deadline,
427 &coin_sig, 436 &coin_sig,
@@ -534,6 +543,8 @@ deposit_traits (void *cls,
534 &ds->merchant_priv), 543 &ds->merchant_priv),
535 TALER_TESTING_make_trait_amount_obj (0, 544 TALER_TESTING_make_trait_amount_obj (0,
536 &ds->amount), 545 &ds->amount),
546 TALER_TESTING_make_trait_absolute_time (0,
547 &ds->exchange_timestamp),
537 TALER_TESTING_trait_end () 548 TALER_TESTING_trait_end ()
538 }; 549 };
539 550
@@ -599,12 +610,12 @@ TALER_TESTING_cmd_deposit (const char *label,
599 label); 610 label);
600 GNUNET_assert (0); 611 GNUNET_assert (0);
601 } 612 }
602 ds->timestamp = GNUNET_TIME_absolute_get (); 613 ds->wallet_timestamp = GNUNET_TIME_absolute_get ();
603 (void) GNUNET_TIME_round_abs (&ds->timestamp); 614 (void) GNUNET_TIME_round_abs (&ds->wallet_timestamp);
604 615
605 json_object_set_new (ds->contract_terms, 616 json_object_set_new (ds->contract_terms,
606 "timestamp", 617 "timestamp",
607 GNUNET_JSON_from_time_abs (ds->timestamp)); 618 GNUNET_JSON_from_time_abs (ds->wallet_timestamp));
608 if (0 != refund_deadline.rel_value_us) 619 if (0 != refund_deadline.rel_value_us)
609 { 620 {
610 ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline); 621 ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
@@ -687,12 +698,12 @@ TALER_TESTING_cmd_deposit_with_ref (const char *label,
687 label); 698 label);
688 GNUNET_assert (0); 699 GNUNET_assert (0);
689 } 700 }
690 ds->timestamp = GNUNET_TIME_absolute_get (); 701 ds->wallet_timestamp = GNUNET_TIME_absolute_get ();
691 (void) GNUNET_TIME_round_abs (&ds->timestamp); 702 (void) GNUNET_TIME_round_abs (&ds->wallet_timestamp);
692 703
693 json_object_set_new (ds->contract_terms, 704 json_object_set_new (ds->contract_terms,
694 "timestamp", 705 "timestamp",
695 GNUNET_JSON_from_time_abs (ds->timestamp)); 706 GNUNET_JSON_from_time_abs (ds->wallet_timestamp));
696 if (0 != refund_deadline.rel_value_us) 707 if (0 != refund_deadline.rel_value_us)
697 { 708 {
698 ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline); 709 ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c
index 356528009..cff2884aa 100644
--- a/src/testing/testing_api_cmd_insert_deposit.c
+++ b/src/testing/testing_api_cmd_insert_deposit.c
@@ -58,6 +58,11 @@ struct InsertDepositState
58 struct GNUNET_TIME_Relative wire_deadline; 58 struct GNUNET_TIME_Relative wire_deadline;
59 59
60 /** 60 /**
61 * When did the exchange receive the deposit?
62 */
63 struct GNUNET_TIME_Absolute exchange_timestamp;
64
65 /**
61 * Amount to deposit, inclusive of deposit fee. 66 * Amount to deposit, inclusive of deposit fee.
62 */ 67 */
63 const char *amount_with_fee; 68 const char *amount_with_fee;
@@ -210,6 +215,7 @@ insert_deposit_run (void *cls,
210 (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 215 (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
211 ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls, 216 ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls,
212 ids->dbc->session, 217 ids->dbc->session,
218 ids->exchange_timestamp,
213 &deposit)) || 219 &deposit)) ||
214 (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 220 (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
215 ids->dbc->plugin->commit (ids->dbc->plugin->cls, 221 ids->dbc->plugin->commit (ids->dbc->plugin->cls,
@@ -275,6 +281,7 @@ insert_deposit_traits (void *cls,
275 * @param dbc collects database plugin and session handles. 281 * @param dbc collects database plugin and session handles.
276 * @param merchant_name Human-readable name of the merchant. 282 * @param merchant_name Human-readable name of the merchant.
277 * @param merchant_account merchant's account name (NOT a payto:// URI) 283 * @param merchant_account merchant's account name (NOT a payto:// URI)
284 * @param exchange_timestamp when did the exchange receive the deposit
278 * @param wire_deadline point in time where the aggregator should have 285 * @param wire_deadline point in time where the aggregator should have
279 * wired money to the merchant. 286 * wired money to the merchant.
280 * @param amount_with_fee amount to deposit (inclusive of deposit fee) 287 * @param amount_with_fee amount to deposit (inclusive of deposit fee)
@@ -282,21 +289,24 @@ insert_deposit_traits (void *cls,
282 * @return the command. 289 * @return the command.
283 */ 290 */
284struct TALER_TESTING_Command 291struct TALER_TESTING_Command
285TALER_TESTING_cmd_insert_deposit (const char *label, 292TALER_TESTING_cmd_insert_deposit (
286 const struct 293 const char *label,
287 TALER_TESTING_DatabaseConnection *dbc, 294 const struct TALER_TESTING_DatabaseConnection *dbc,
288 const char *merchant_name, 295 const char *merchant_name,
289 const char *merchant_account, 296 const char *merchant_account,
290 struct GNUNET_TIME_Relative wire_deadline, 297 struct GNUNET_TIME_Absolute exchange_timestamp,
291 const char *amount_with_fee, 298 struct GNUNET_TIME_Relative wire_deadline,
292 const char *deposit_fee) 299 const char *amount_with_fee,
300 const char *deposit_fee)
293{ 301{
294 struct InsertDepositState *ids; 302 struct InsertDepositState *ids;
295 303
304 GNUNET_TIME_round_abs (&exchange_timestamp);
296 ids = GNUNET_new (struct InsertDepositState); 305 ids = GNUNET_new (struct InsertDepositState);
297 ids->dbc = dbc; 306 ids->dbc = dbc;
298 ids->merchant_name = merchant_name; 307 ids->merchant_name = merchant_name;
299 ids->merchant_account = merchant_account; 308 ids->merchant_account = merchant_account;
309 ids->exchange_timestamp = exchange_timestamp;
300 ids->wire_deadline = wire_deadline; 310 ids->wire_deadline = wire_deadline;
301 ids->amount_with_fee = amount_with_fee; 311 ids->amount_with_fee = amount_with_fee;
302 ids->deposit_fee = deposit_fee; 312 ids->deposit_fee = deposit_fee;