diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-09-24 19:03:37 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-09-24 19:03:37 +0200 |
commit | 08b2623684a09bf5bb1e30282b1fd314df02b3e7 (patch) | |
tree | 17459816875abcfb42b6d79d8ff18767a2148b24 /src | |
parent | cc15874189dcfb4336921559ce94f4234daa3ca2 (diff) |
combine deposit confirmation signatures into one big signature
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/taler-merchant-httpd_post-orders-ID-abort.c | 5 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_post-orders-ID-pay.c | 235 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-get-orders-ID.c | 15 | ||||
-rw-r--r-- | src/backenddb/Makefile.am | 1 | ||||
-rw-r--r-- | src/backenddb/merchant-0001.sql | 50 | ||||
-rw-r--r-- | src/backenddb/pg_increase_refund.c | 15 | ||||
-rw-r--r-- | src/backenddb/pg_insert_deposit.c | 69 | ||||
-rw-r--r-- | src/backenddb/pg_insert_deposit.h | 33 | ||||
-rw-r--r-- | src/backenddb/pg_insert_transfer_details.c | 60 | ||||
-rw-r--r-- | src/backenddb/pg_lookup_deposits.c | 23 | ||||
-rw-r--r-- | src/backenddb/pg_refund_coin.c | 14 | ||||
-rw-r--r-- | src/backenddb/plugin_merchantdb_postgres.c | 167 | ||||
-rw-r--r-- | src/backenddb/test_merchantdb.c | 124 | ||||
-rw-r--r-- | src/include/taler_merchantdb_plugin.h | 132 | ||||
-rwxr-xr-x | src/testing/test_merchant_transfer_tracking.sh | 7 |
15 files changed, 502 insertions, 448 deletions
diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-abort.c b/src/backend/taler-merchant-httpd_post-orders-ID-abort.c index 09ac8acb..7b6bc7b5 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-abort.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-abort.c @@ -619,7 +619,6 @@ find_next_exchange (struct AbortContext *ac) * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin * @param refund_fee fee the exchange will charge for refunding this coin - * @param wire_fee wire fee the exchange of this coin charges */ static void refund_coins (void *cls, @@ -627,8 +626,7 @@ refund_coins (void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee) + const struct TALER_Amount *refund_fee) { struct AbortContext *ac = cls; struct GNUNET_TIME_Timestamp now; @@ -636,7 +634,6 @@ refund_coins (void *cls, (void) amount_with_fee; (void) deposit_fee; (void) refund_fee; - (void) wire_fee; now = GNUNET_TIME_timestamp_get (); for (unsigned int i = 0; i<ac->coins_cnt; i++) { diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c index fd17f029..c99a6c64 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -90,11 +90,6 @@ struct DepositConfirmation struct TALER_Amount refund_fee; /** - * Wire fee charged by the exchange of this coin. - */ - struct TALER_Amount wire_fee; - - /** * If a minimum age was required (i. e. pc->minimum_age is large enough), * this is the signature of the minimum age (as a single uint8_t), using the * private key to the corresponding age group. Might be all zeroes for no @@ -902,6 +897,107 @@ check_kyc (struct PayContext *pc, /** + * Do database transaction for a completed batch deposit. + * + * @param eg group that completed + * @param dr response from the server + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +batch_deposit_transaction (const struct ExchangeGroup *eg, + const struct TALER_EXCHANGE_BatchDepositResult *dr) +{ + const struct PayContext *pc = eg->pc; + enum GNUNET_DB_QueryStatus qs; + struct TALER_Amount total_without_fees = { 0 }; + uint64_t b_dep_serial; + uint32_t off = 0; + bool found = false; + + for (unsigned int i = 0; i<pc->coins_cnt; i++) + { + struct DepositConfirmation *dc = &pc->dc[i]; + struct TALER_Amount amount_without_fees; + + /* might want to group deposits by batch more explicitly ... */ + if (0 != strcmp (eg->exchange_url, + dc->exchange_url)) + continue; + if (dc->found_in_db) + continue; + GNUNET_assert (0 <= + TALER_amount_subtract (&amount_without_fees, + &dc->cdd.amount, + &dc->deposit_fee)); + if (! found) + { + found = true; + total_without_fees = amount_without_fees; + } + else + { + GNUNET_assert ( + 0 <= + TALER_amount_add (&total_without_fees, + &total_without_fees, + &amount_without_fees)); + } + } + qs = TMH_db->insert_deposit_confirmation ( + TMH_db->cls, + pc->hc->instance->settings.id, + dr->details.ok.deposit_timestamp, + &pc->h_contract_terms, + eg->exchange_url, + &total_without_fees, + &eg->wire_fee, + &pc->wm->h_wire, + dr->details.ok.exchange_sig, + dr->details.ok.exchange_pub, + &b_dep_serial); + if (qs <= 0) + return qs; /* Entire batch already known or failure, we're done */ + + if (! found) + { + /* All coins already done, but the batch was not? Invariant violation! */ + GNUNET_break (0); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + for (unsigned int i = 0; i<pc->coins_cnt; i++) + { + struct DepositConfirmation *dc = &pc->dc[i]; + + /* might want to group deposits by batch more explicitly ... */ + if (0 != strcmp (eg->exchange_url, + dc->exchange_url)) + continue; + if (dc->found_in_db) + continue; + /* NOTE: We might want to check if the order was fully paid concurrently + by some other wallet here, and if so, issue an auto-refund. Right now, + it is possible to over-pay if two wallets literally make a concurrent + payment, as the earlier check for 'paid' is not in the same transaction + scope as this 'insert' operation. */ + qs = TMH_db->insert_deposit ( + TMH_db->cls, + off++, /* might want to group deposits by batch more explicitly ... */ + b_dep_serial, + &dc->cdd.coin_pub, + &dc->cdd.coin_sig, + &dc->cdd.amount, + &dc->deposit_fee, + &dc->refund_fee); + if (qs < 0) + return qs; + GNUNET_break (qs > 0); + } + return qs; +} + + +/** * Handle case where the batch deposit completed * with a status of #MHD_HTTP_OK. * @@ -924,8 +1020,6 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, pc->hc->instance->settings.id); for (unsigned int r = 0; r<MAX_RETRIES; r++) { - unsigned int j = 0; - TMH_db->preflight (TMH_db->cls); if (GNUNET_OK != TMH_db->start (TMH_db->cls, @@ -940,50 +1034,19 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, TMH_pack_exchange_reply (&dr->hr))); return; } - for (unsigned int i = 0; i<pc->coins_cnt; i++) + qs = batch_deposit_transaction (eg, + dr); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) { - struct DepositConfirmation *dc = &pc->dc[i]; - - if (0 != strcmp (eg->exchange_url, - pc->dc[i].exchange_url)) - continue; - if (dc->found_in_db) - continue; - /* NOTE: We might want to check if the order was fully paid concurrently - by some other wallet here, and if so, issue an auto-refund. Right now, - it is possible to over-pay if two wallets literally make a concurrent - payment, as the earlier check for 'paid' is not in the same transaction - scope as this 'insert' operation. */ - GNUNET_assert (j < dr->details.ok.num_signatures); - qs = TMH_db->insert_deposit ( - TMH_db->cls, - pc->hc->instance->settings.id, - dr->details.ok.deposit_timestamp, - &pc->h_contract_terms, - &dc->cdd.coin_pub, - dc->exchange_url, - &dc->cdd.amount, - &dc->deposit_fee, - &dc->refund_fee, - &dc->wire_fee, - &pc->wm->h_wire, - &dr->details.ok.exchange_sigs[j++], - dr->details.ok.exchange_pub); - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - { - TMH_db->rollback (TMH_db->cls); - break; - } - if (0 > qs) - { - /* Always report on hard error as well to enable diagnostics */ - GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); - /* Forward error including 'proof' for the body */ - resume_pay_with_error (pc, - TALER_EC_GENERIC_DB_STORE_FAILED, - "insert_deposit"); - return; - } + TMH_db->rollback (TMH_db->cls); + continue; + } + if (GNUNET_DB_STATUS_HARD_ERROR == qs) + { + GNUNET_break (0); + resume_pay_with_error (pc, + TALER_EC_GENERIC_DB_COMMIT_FAILED, + "batch_deposit_transaction"); } qs = TMH_db->commit (TMH_db->cls); if (GNUNET_DB_STATUS_SOFT_ERROR == qs) @@ -999,7 +1062,7 @@ handle_batch_deposit_ok (struct ExchangeGroup *eg, "insert_deposit"); } break; /* DB transaction succeeded */ - } /* FOR DB retries */ + } if (GNUNET_DB_STATUS_SOFT_ERROR == qs) { resume_pay_with_error (pc, @@ -1387,7 +1450,6 @@ AGE_FAIL: eg->exchange_url)) continue; cdds[i] = dc->cdd; - dc->wire_fee = eg->wire_fee; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Initiating batch deposit with %u coins\n", @@ -1509,7 +1571,6 @@ start_batch_deposits (struct PayContext *pc) * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin * @param refund_fee fee the exchange will charge for refunding this coin - * @param wire_fee wire fee the exchange of this coin charges */ static void check_coin_paid (void *cls, @@ -1517,8 +1578,7 @@ check_coin_paid (void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee) + const struct TALER_Amount *refund_fee) { struct PayContext *pc = cls; @@ -1551,7 +1611,6 @@ check_coin_paid (void *cls, deposit_fee)); dc->deposit_fee = *deposit_fee; dc->refund_fee = *refund_fee; - dc->wire_fee = *wire_fee; dc->cdd.amount = *amount_with_fee; dc->found_in_db = true; pc->pending--; @@ -1623,8 +1682,33 @@ check_payment_sufficient (struct PayContext *pc) (0 == pc->amount.fraction)); } + total_wire_fee = pc->egs[0]->wire_fee; + for (unsigned int i = 1; i < pc->num_exchanges; i++) + { + if (GNUNET_OK != + TALER_amount_cmp_currency (&total_wire_fee, + &pc->egs[i]->wire_fee)) + { + GNUNET_break_op (0); + resume_pay_with_error (pc, + TALER_EC_GENERIC_CURRENCY_MISMATCH, + total_wire_fee.currency); + return false; + } + if (0 > + TALER_amount_add (&total_wire_fee, + &total_wire_fee, + &pc->egs[i]->wire_fee)) + { + GNUNET_break (0); + resume_pay_with_error (pc, + TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, + "could not add exchange wire fee to total"); + return false; + } + } + acc_fee = pc->dc[0].deposit_fee; - total_wire_fee = pc->dc[0].wire_fee; acc_amount = pc->dc[0].cdd.amount; /** @@ -1663,43 +1747,6 @@ check_payment_sufficient (struct PayContext *pc) return false; } - /* If exchange differs, add wire fee */ - { - bool new_exchange = true; - - for (unsigned int j = 0; j<i; j++) - if (0 == strcasecmp (dc->exchange_url, - pc->dc[j].exchange_url)) - { - new_exchange = false; - break; - } - - if (! new_exchange) - continue; - - if (GNUNET_OK != - TALER_amount_cmp_currency (&total_wire_fee, - &dc->wire_fee)) - { - GNUNET_break_op (0); - resume_pay_with_error (pc, - TALER_EC_GENERIC_CURRENCY_MISMATCH, - total_wire_fee.currency); - return false; - } - if (0 > - TALER_amount_add (&total_wire_fee, - &total_wire_fee, - &dc->wire_fee)) - { - GNUNET_break (0); - resume_pay_with_error (pc, - TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, - "could not add exchange wire fee to total"); - return false; - } - } } /* deposit loop */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, diff --git a/src/backend/taler-merchant-httpd_private-get-orders-ID.c b/src/backend/taler-merchant-httpd_private-get-orders-ID.c index f732dc84..20ed5fa7 100644 --- a/src/backend/taler-merchant-httpd_private-get-orders-ID.c +++ b/src/backend/taler-merchant-httpd_private-get-orders-ID.c @@ -804,13 +804,14 @@ process_refunds_cb (void *cls, * @a wtid over the total amount happened? */ static void -process_transfer_details (void *cls, - const struct TALER_WireTransferIdentifierRawP *wtid, - const char *exchange_url, - struct GNUNET_TIME_Timestamp execution_time, - const struct TALER_Amount *deposit_value, - const struct TALER_Amount *deposit_fee, - bool transfer_confirmed) +process_transfer_details ( + void *cls, + const struct TALER_WireTransferIdentifierRawP *wtid, + const char *exchange_url, + struct GNUNET_TIME_Timestamp execution_time, + const struct TALER_Amount *deposit_value, + const struct TALER_Amount *deposit_fee, + bool transfer_confirmed) { struct GetOrderRequestContext *gorc = cls; json_t *wire_details = gorc->wire_details; diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am index 64b9883e..22041a1d 100644 --- a/src/backenddb/Makefile.am +++ b/src/backenddb/Makefile.am @@ -125,6 +125,7 @@ libtaler_plugin_merchantdb_postgres_la_SOURCES = \ pg_lookup_deposits.h pg_lookup_deposits.c \ pg_insert_exchange_signkey.h pg_insert_exchange_signkey.c \ pg_insert_deposit.h pg_insert_deposit.c \ + pg_insert_deposit_confirmation.h pg_insert_deposit_confirmation.c \ pg_lookup_refunds.h pg_lookup_refunds.c \ pg_mark_contract_paid.h pg_mark_contract_paid.c \ pg_refund_coin.h pg_refund_coin.c \ diff --git a/src/backenddb/merchant-0001.sql b/src/backenddb/merchant-0001.sql index 4e2b0639..d6b25d8d 100644 --- a/src/backenddb/merchant-0001.sql +++ b/src/backenddb/merchant-0001.sql @@ -383,35 +383,61 @@ CREATE INDEX IF NOT EXISTS merchant_contract_terms_by_merchant_session_and_fulfi ---------------- Payment and refunds --------------------------- -CREATE TABLE IF NOT EXISTS merchant_deposits - (deposit_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY +CREATE TABLE IF NOT EXISTS merchant_deposit_confirmations + (deposit_confirmation_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,order_serial BIGINT REFERENCES merchant_contract_terms (order_serial) ON DELETE CASCADE ,deposit_timestamp INT8 NOT NULL - ,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32) ,exchange_url TEXT NOT NULL - ,amount_with_fee taler_amount_currency NOT NULL - ,deposit_fee taler_amount_currency NOT NULL - ,refund_fee taler_amount_currency NOT NULL + ,total_without_fee taler_amount_currency NOT NULL ,wire_fee taler_amount_currency NOT NULL ,signkey_serial BIGINT NOT NULL REFERENCES merchant_exchange_signing_keys (signkey_serial) ON DELETE CASCADE ,exchange_sig BYTEA NOT NULL CHECK (LENGTH(exchange_sig)=64) ,account_serial BIGINT NOT NULL REFERENCES merchant_accounts (account_serial) ON DELETE CASCADE - ,UNIQUE (order_serial, coin_pub) + ,UNIQUE (order_serial, exchange_sig) ); -COMMENT ON TABLE merchant_deposits +COMMENT ON TABLE merchant_deposit_confirmations IS 'Table with the deposit confirmations for each coin we deposited at the exchange'; -COMMENT ON COLUMN merchant_deposits.signkey_serial +COMMENT ON COLUMN merchant_deposit_confirmations.signkey_serial IS 'Online signing key of the exchange on the deposit confirmation'; -COMMENT ON COLUMN merchant_deposits.deposit_timestamp +COMMENT ON COLUMN merchant_deposit_confirmations.deposit_timestamp IS 'Time when the exchange generated the deposit confirmation'; -COMMENT ON COLUMN merchant_deposits.exchange_sig +COMMENT ON COLUMN merchant_deposit_confirmations.exchange_sig IS 'Signature of the exchange over the deposit confirmation'; -COMMENT ON COLUMN merchant_deposits.wire_fee +COMMENT ON COLUMN merchant_deposit_confirmations.wire_fee IS 'We MAY want to see if we should try to get this via merchant_exchange_wire_fees (not sure, may be too complicated with the date range, etc.)'; + +CREATE TABLE IF NOT EXISTS merchant_deposits + (deposit_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY + ,coin_offset INT4 NOT NULL + ,deposit_confirmation_serial BIGINT NOT NULL + REFERENCES merchant_deposit_confirmations (deposit_confirmation_serial) ON DELETE CASCADE + ,coin_pub BYTEA NOT NULL CHECK (LENGTH(coin_pub)=32) + ,coin_sig BYTEA NOT NULL CHECK (LENGTH(coin_sig)=64) + ,amount_with_fee taler_amount_currency NOT NULL + ,deposit_fee taler_amount_currency NOT NULL + ,refund_fee taler_amount_currency NOT NULL + ,UNIQUE (deposit_confirmation_serial, coin_pub) + ); +COMMENT ON TABLE merchant_deposits + IS 'Table with the deposit details for each coin we deposited at the exchange'; +COMMENT ON COLUMN merchant_deposits.coin_offset + IS 'Offset of this coin in the batch'; +COMMENT ON COLUMN merchant_deposits.deposit_confirmation_serial + IS 'Reference to the deposit confirmation of the exchange'; +COMMENT ON COLUMN merchant_deposits.coin_pub + IS 'Public key of the coin that was deposited'; +COMMENT ON COLUMN merchant_deposits.amount_with_fee + IS 'Total amount (incl. fee) of the coin that was deposited'; +COMMENT ON COLUMN merchant_deposits.deposit_fee + IS 'Deposit fee (for this coin) that was paid'; +COMMENT ON COLUMN merchant_deposits.refund_fee + IS 'How high would the refund fee be (for this coin)'; + + CREATE TABLE IF NOT EXISTS merchant_refunds (refund_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY ,order_serial BIGINT NOT NULL diff --git a/src/backenddb/pg_increase_refund.c b/src/backenddb/pg_increase_refund.c index 5fd548d7..d274b1e9 100644 --- a/src/backenddb/pg_increase_refund.c +++ b/src/backenddb/pg_increase_refund.c @@ -364,7 +364,7 @@ process_deposits_for_refund_cb ( GNUNET_PQ_query_param_auto_from_type (&rcd[i].coin_pub), GNUNET_PQ_query_param_string (ctx->reason), TALER_PQ_query_param_amount_with_currency (pg->conn, - increment), + increment), GNUNET_PQ_query_param_end }; @@ -451,20 +451,21 @@ TMH_PG_increase_refund (void *cls, PREPARE (pg, "find_deposits_for_refund", "SELECT" - " coin_pub" - ",order_serial" - ",amount_with_fee" - " FROM merchant_deposits" + " dep.coin_pub" + ",dco.order_serial" + ",dep.amount_with_fee" + " FROM merchant_deposits dep" + " JOIN merchant_deposit_confirmations dco" + " USING (deposit_confirmation_serial)" " WHERE order_serial=" " (SELECT order_serial" " FROM merchant_contract_terms" " WHERE order_id=$2" - " AND paid=TRUE" + " AND paid" " AND merchant_serial=" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1))"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asked to refund %s on order %s\n", TALER_amount2s (refund), diff --git a/src/backenddb/pg_insert_deposit.c b/src/backenddb/pg_insert_deposit.c index f99c6f44..8e77e24a 100644 --- a/src/backenddb/pg_insert_deposit.c +++ b/src/backenddb/pg_insert_deposit.c @@ -30,85 +30,46 @@ enum GNUNET_DB_QueryStatus TMH_PG_insert_deposit ( void *cls, - const char *instance_id, - struct GNUNET_TIME_Timestamp deposit_timestamp, - const struct TALER_PrivateContractHashP *h_contract_terms, + uint32_t offset, + uint64_t deposit_confirmation_serial, const struct TALER_CoinSpendPublicKeyP *coin_pub, - const char *exchange_url, + const struct TALER_CoinSpendSignatureP *coin_sig, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee, - const struct TALER_MerchantWireHashP *h_wire, - const struct TALER_ExchangeSignatureP *exchange_sig, - const struct TALER_ExchangePublicKeyP *exchange_pub) + const struct TALER_Amount *refund_fee) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_string (instance_id), - GNUNET_PQ_query_param_auto_from_type (h_contract_terms), - GNUNET_PQ_query_param_timestamp (&deposit_timestamp), /* $3 */ + GNUNET_PQ_query_param_uint64 (&deposit_confirmation_serial), + GNUNET_PQ_query_param_uint32 (&offset), GNUNET_PQ_query_param_auto_from_type (coin_pub), - GNUNET_PQ_query_param_string (exchange_url), + GNUNET_PQ_query_param_auto_from_type (coin_sig), TALER_PQ_query_param_amount_with_currency (pg->conn, - amount_with_fee), /* $6 */ + amount_with_fee), TALER_PQ_query_param_amount_with_currency (pg->conn, - deposit_fee), /* $7 */ + deposit_fee), TALER_PQ_query_param_amount_with_currency (pg->conn, - refund_fee), /* $8 */ - TALER_PQ_query_param_amount_with_currency (pg->conn, - wire_fee), /* $9 */ - GNUNET_PQ_query_param_auto_from_type (h_wire), /* $10 */ - GNUNET_PQ_query_param_auto_from_type (exchange_sig), /* $11 */ - GNUNET_PQ_query_param_auto_from_type (exchange_pub), /* $12 */ + refund_fee), GNUNET_PQ_query_param_end }; /* no preflight check here, run in transaction by caller! */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Storing deposit for instance `%s' h_contract_terms `%s', coin_pub: `%s', amount_with_fee: %s\n", - instance_id, - GNUNET_h2s (&h_contract_terms->hash), + "Storing deposit for coin_pub: `%s', amount_with_fee: %s\n", TALER_B2S (coin_pub), TALER_amount2s (amount_with_fee)); check_connection (pg); PREPARE (pg, "insert_deposit", - "WITH md AS" - " (SELECT account_serial, merchant_serial" - " FROM merchant_accounts" - " WHERE h_wire=$10" - " AND merchant_serial=" - " (SELECT merchant_serial" - " FROM merchant_instances" - " WHERE merchant_id=$1))" - ", ed AS" - " (SELECT signkey_serial" - " FROM merchant_exchange_signing_keys" - " WHERE exchange_pub=$12" - " ORDER BY start_date DESC" - " LIMIT 1)" "INSERT INTO merchant_deposits" - "(order_serial" - ",deposit_timestamp" + "(deposit_confirmation_serial" + ",coin_offset" ",coin_pub" - ",exchange_url" + ",coin_sig" ",amount_with_fee" ",deposit_fee" ",refund_fee" - ",wire_fee" - ",exchange_sig" - ",signkey_serial" - ",account_serial)" - " SELECT " - " order_serial" - " ,$3, $4, $5, $6, $7, $8, $9, $11" - " ,ed.signkey_serial" - " ,md.account_serial" - " FROM merchant_contract_terms" - " JOIN md USING (merchant_serial)" - " FULL OUTER JOIN ed ON TRUE" - " WHERE h_contract_terms=$2"); + ") VALUES ($1, $2, $3, $4, $5, $6, $7)"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "insert_deposit", params); diff --git a/src/backenddb/pg_insert_deposit.h b/src/backenddb/pg_insert_deposit.h index 999d9367..94af2bf4 100644 --- a/src/backenddb/pg_insert_deposit.h +++ b/src/backenddb/pg_insert_deposit.h @@ -29,34 +29,25 @@ * Insert payment confirmation from the exchange into the database. * * @param cls closure - * @param instance_id instance to lookup deposits for - * @param deposit_timestamp time when the exchange generated the deposit confirmation - * @param h_contract_terms proposal data's hashcode + * @param offset offset of the coin in the batch + * @param deposit_confirmation_serial which deposit confirmation is this coin part of * @param coin_pub public key of the coin - * @param exchange_url URL of the exchange that issued @a coin_pub + * @param coin_sig signature of the coin * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin * @param wire_fee wire fee the exchange charges * @param refund_fee fee the exchange charges to refund this coin - * @param h_wire hash of the wire details of the target account of the merchant - * @param exchange_sig signature from exchange that coin was accepted - * @param exchange_pub signgin key that was used for @a exchange_sig * @return transaction status */ enum GNUNET_DB_QueryStatus -TMH_PG_insert_deposit (void *cls, - const char *instance_id, - struct GNUNET_TIME_Timestamp deposit_timestamp, - const struct - TALER_PrivateContractHashP *h_contract_terms, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const char *exchange_url, - const struct TALER_Amount *amount_with_fee, - const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee, - const struct TALER_MerchantWireHashP *h_wire, - const struct TALER_ExchangeSignatureP *exchange_sig, - const struct TALER_ExchangePublicKeyP *exchange_pub); +TMH_PG_insert_deposit ( + void *cls, + uint32_t offset, + uint64_t deposit_confirmation_serial, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *deposit_fee, + const struct TALER_Amount *refund_fee); #endif diff --git a/src/backenddb/pg_insert_transfer_details.c b/src/backenddb/pg_insert_transfer_details.c index a4f69989..66859649 100644 --- a/src/backenddb/pg_insert_transfer_details.c +++ b/src/backenddb/pg_insert_transfer_details.c @@ -87,35 +87,47 @@ TMH_PG_insert_transfer_details ( ",offset_in_exchange_list" ",exchange_deposit_value" ",exchange_deposit_fee) " - "SELECT deposit_serial, $1, $2, $3, $4" - " FROM merchant_deposits" - " JOIN merchant_contract_terms USING (order_serial)" - " WHERE coin_pub=$5" - " AND h_contract_terms=$6" - " AND merchant_serial=" + "SELECT dep.deposit_serial, $1, $2, $3, $4" + " FROM merchant_deposits dep" + " JOIN merchant_deposit_confirmations dcon" + " USING (deposit_confirmation_serial)" + " JOIN merchant_contract_terms cterm" + " USING (order_serial)" + " WHERE dep.coin_pub=$5" + " AND cterm.h_contract_terms=$6" + " AND cterm.merchant_serial=" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$7)"); PREPARE (pg, "update_wired_by_coin_pub", - "WITH os AS" /* select orders affected by the coin */ - "(SELECT order_serial" - " FROM merchant_deposits" - " WHERE coin_pub=$1)" + "WITH affected_orders AS" /* select orders affected by the coin */ + "(SELECT mcon.order_serial" + " FROM merchant_deposits dep" + /* Next 2 joins ensure transfers exist in the first place */ + " JOIN merchant_deposit_to_transfer" + " USING (deposit_serial)" + " JOIN merchant_transfers mtrans" + " USING (credit_serial)" + " JOIN merchant_deposit_confirmations mcon" + " USING (deposit_confirmation_serial)" + " WHERE dep.coin_pub=$1)" "UPDATE merchant_contract_terms " " SET wired=TRUE " " WHERE order_serial IN " - " (SELECT order_serial FROM merchant_deposits" /* only orders for which NO un-wired coin exists*/ + " (SELECT order_serial" + " FROM merchant_deposit_confirmations dcon" + " JOIN affected_orders" + " USING (order_serial)" " WHERE NOT EXISTS " - " (SELECT order_serial FROM merchant_deposits" /* orders for which ANY un-wired coin exists */ - " JOIN os USING (order_serial)" /* filter early */ - " WHERE deposit_serial NOT IN" - " (SELECT deposit_serial " /* all coins associated with order that WERE wired */ - " FROM merchant_deposits " - " JOIN os USING (order_serial)" /* filter early */ - " JOIN merchant_deposit_to_transfer USING (deposit_serial)" - " JOIN merchant_transfers USING (credit_serial)" - " WHERE confirmed=TRUE)))"); + " (SELECT 1" + " FROM merchant_deposits dep" + " JOIN merchant_deposit_to_transfer" + " USING (deposit_serial)" + " JOIN merchant_transfers mtrans" + " USING (credit_serial)" + " WHERE dep.deposit_confirmation_serial = dcon.deposit_confirmation_serial" + " AND NOT mtrans.confirmed))"); RETRY: if (MAX_RETRIES < ++retries) @@ -175,9 +187,9 @@ RETRY: struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&credit_serial), TALER_PQ_query_param_amount_with_currency (pg->conn, - &td->total_amount), + &td->total_amount), TALER_PQ_query_param_amount_with_currency (pg->conn, - &td->wire_fee), + &td->wire_fee), GNUNET_PQ_query_param_timestamp (&td->execution_time), GNUNET_PQ_query_param_auto_from_type (&td->exchange_sig), GNUNET_PQ_query_param_auto_from_type (&td->exchange_pub), @@ -219,9 +231,9 @@ RETRY: GNUNET_PQ_query_param_uint64 (&credit_serial), GNUNET_PQ_query_param_uint64 (&i64), TALER_PQ_query_param_amount_with_currency (pg->conn, - &d->coin_value), + &d->coin_value), TALER_PQ_query_param_amount_with_currency (pg->conn, - &d->coin_fee), /* deposit fee */ + &d->coin_fee), /* deposit fee */ GNUNET_PQ_query_param_auto_from_type (&d->coin_pub), GNUNET_PQ_query_param_auto_from_type (&d->h_contract_terms), GNUNET_PQ_query_param_string (instance_id), diff --git a/src/backenddb/pg_lookup_deposits.c b/src/backenddb/pg_lookup_deposits.c index 242d7bbb..2440f62c 100644 --- a/src/backenddb/pg_lookup_deposits.c +++ b/src/backenddb/pg_lookup_deposits.c @@ -73,7 +73,6 @@ lookup_deposits_cb (void *cls, struct TALER_Amount amount_with_fee; struct TALER_Amount deposit_fee; struct TALER_Amount refund_fee; - struct TALER_Amount wire_fee; char *exchange_url; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_string ("exchange_url", @@ -86,8 +85,6 @@ lookup_deposits_cb (void *cls, &deposit_fee), TALER_PQ_result_spec_amount_with_currency ("refund_fee", &refund_fee), - TALER_PQ_result_spec_amount_with_currency ("wire_fee", - &wire_fee), GNUNET_PQ_result_spec_end }; @@ -105,8 +102,7 @@ lookup_deposits_cb (void *cls, &coin_pub, &amount_with_fee, &deposit_fee, - &refund_fee, - &wire_fee); + &refund_fee); GNUNET_PQ_cleanup_result (rs); } ldc->qs = num_results; @@ -142,14 +138,15 @@ TMH_PG_lookup_deposits ( PREPARE (pg, "lookup_deposits", "SELECT" - " exchange_url" - ",coin_pub" - ",amount_with_fee" - ",deposit_fee" - ",refund_fee" - ",wire_fee" - " FROM merchant_deposits" - " WHERE order_serial=" + " dcom.exchange_url" + ",dep.coin_pub" + ",dep.amount_with_fee" + ",dep.deposit_fee" + ",dep.refund_fee" + " FROM merchant_deposits dep" + " JOIN merchant_deposit_confirmations dcom" + " USING (deposit_confirmation_serial)" + " WHERE dcom.order_serial=" " (SELECT order_serial" " FROM merchant_contract_terms" " WHERE h_contract_terms=$2" diff --git a/src/backenddb/pg_refund_coin.c b/src/backenddb/pg_refund_coin.c index afbcebcc..1bde2974 100644 --- a/src/backenddb/pg_refund_coin.c +++ b/src/backenddb/pg_refund_coin.c @@ -53,15 +53,17 @@ TMH_PG_refund_coin (void *cls, ",refund_amount" ") " "SELECT " - " order_serial" + " dcon.order_serial" ",0" /* rtransaction_id always 0 for /abort */ ",$3" - ",coin_pub" + ",dep.coin_pub" ",$5" - ",amount_with_fee" - " FROM merchant_deposits" - " WHERE coin_pub=$4" - " AND order_serial=" + ",dep.amount_with_fee" + " FROM merchant_deposits dep" + " JOIN merchant_deposit_confirmations dcon" + " USING (deposit_confirmation_serial)" + " WHERE dep.coin_pub=$4" + " AND dcon.order_serial=" " (SELECT order_serial" " FROM merchant_contract_terms" " WHERE h_contract_terms=$2" diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 3682e5c1..30def849 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -89,6 +89,7 @@ #include "pg_lookup_deposits.h" #include "pg_insert_exchange_signkey.h" #include "pg_insert_deposit.h" +#include "pg_insert_deposit_confirmation.h" #include "pg_lookup_refunds.h" #include "pg_mark_contract_paid.h" #include "pg_select_account_by_uri.h" @@ -3060,52 +3061,65 @@ postgres_connect (void *cls) /* for postgres_lookup_deposits_by_order() */ GNUNET_PQ_make_prepare ("lookup_deposits_by_order", "SELECT" - " deposit_serial" - ",exchange_url" - ",h_wire" - ",amount_with_fee" - ",deposit_fee" - ",coin_pub" - " FROM merchant_deposits" - " JOIN merchant_accounts USING (account_serial)" - " WHERE order_serial=$1"), + " dep.deposit_serial" + ",mcon.exchange_url" + ",acc.h_wire" + ",dep.amount_with_fee" + ",dep.deposit_fee" + ",dep.coin_pub" + " FROM merchant_deposits dep" + " JOIN merchant_deposit_confirmations mcon" + " USING(deposit_confirmation_serial)" + " JOIN merchant_accounts acc" + " USING (account_serial)" + " WHERE mcon.order_serial=$1"), /* for postgres_lookup_transfer_details_by_order() */ GNUNET_PQ_make_prepare ("lookup_transfer_details_by_order", "SELECT" " md.deposit_serial" - ",md.exchange_url" + ",mcon.exchange_url" ",mt.wtid" - ",exchange_deposit_value" - ",exchange_deposit_fee" - ",deposit_timestamp" + ",mtc.exchange_deposit_value" + ",mtc.exchange_deposit_fee" + ",mcon.deposit_timestamp" ",mt.confirmed AS transfer_confirmed" - " FROM merchant_transfer_to_coin" - " JOIN merchant_deposits AS md USING (deposit_serial)" - " JOIN merchant_transfers AS mt USING (credit_serial)" - " WHERE deposit_serial IN" - " (SELECT deposit_serial" - " FROM merchant_deposits" - " WHERE order_serial=$1)"), + " FROM merchant_transfer_to_coin mtc" + " JOIN merchant_deposits md" + " USING (deposit_serial)" + " JOIN merchant_deposit_confirmations mcon" + " USING (deposit_confirmation_serial)" + " JOIN merchant_transfers mt" + " USING (credit_serial)" + " JOIN merchant_accounts acc" + " ON (acc.account_serial = mt.account_serial)" + /* Check that all this is for the same instance */ + " JOIN merchant_contract_terms contracts" + " USING (merchant_serial, order_serial)" + " WHERE mcon.order_serial=$1"), /* for postgres_mark_order_wired() */ GNUNET_PQ_make_prepare ("mark_order_wired", "UPDATE merchant_contract_terms SET" - " wired=true" + " wired=TRUE" " WHERE order_serial=$1"), /* for postgres_lookup_refunds_detailed() */ GNUNET_PQ_make_prepare ("lookup_refunds_detailed", "SELECT" - " refund_serial" - ",refund_timestamp" - ",coin_pub" - ",merchant_deposits.exchange_url" - ",rtransaction_id" - ",reason" - ",refund_amount" + " ref.refund_serial" + ",ref.refund_timestamp" + ",dep.coin_pub" + ",mcon.exchange_url" + ",ref.rtransaction_id" + ",ref.reason" + ",ref.refund_amount" ",merchant_refund_proofs.exchange_sig IS NULL AS pending" - " FROM merchant_refunds" - " JOIN merchant_deposits USING (order_serial, coin_pub)" - " LEFT JOIN merchant_refund_proofs USING (refund_serial)" - " WHERE order_serial=" + " FROM merchant_deposit_confirmations mcon" + " JOIN merchant_deposits dep" + " USING (deposit_confirmation_serial)" + " JOIN merchant_refunds ref" + " USING (order_serial, coin_pub)" + " LEFT JOIN merchant_refund_proofs" + " USING (refund_serial)" + " WHERE mcon.order_serial=" " (SELECT order_serial" " FROM merchant_contract_terms" " WHERE h_contract_terms=$2" @@ -3197,23 +3211,28 @@ postgres_connect (void *cls) /* for postgres_lookup_deposits_by_contract_and_coin() */ GNUNET_PQ_make_prepare ("lookup_deposits_by_contract_and_coin", "SELECT" - " exchange_url" - ",amount_with_fee" - ",deposit_fee" - ",refund_fee" - ",wire_fee" - ",h_wire" - ",deposit_timestamp" - ",refund_deadline" - ",exchange_sig" - ",exchange_pub" - " FROM merchant_contract_terms" - " JOIN merchant_deposits USING (order_serial)" - " JOIN merchant_exchange_signing_keys USING (signkey_serial)" - " JOIN merchant_accounts USING (account_serial)" + " mcon.exchange_url" + ",dep.amount_with_fee" + ",dep.deposit_fee" + ",dep.refund_fee" + ",mcon.wire_fee" + ",acc.h_wire" + ",mcon.deposit_timestamp" + ",mct.refund_deadline" + ",mcon.exchange_sig" + ",msig.exchange_pub" + " FROM merchant_contract_terms mct" + " JOIN merchant_deposit_confirmations mcon" + " USING (order_serial)" + " JOIN merchant_deposits dep" + " USING (deposit_confirmation_serial)" + " JOIN merchant_exchange_signing_keys msig" + " USING (signkey_serial)" + " JOIN merchant_accounts acc" + " USING (account_serial)" " WHERE h_contract_terms=$2" - " AND coin_pub=$3" - " AND merchant_contract_terms.merchant_serial=" + " AND dep.coin_pub=$3" + " AND mct.merchant_serial=" " (SELECT merchant_serial" " FROM merchant_instances" " WHERE merchant_id=$1)"), @@ -3235,29 +3254,39 @@ postgres_connect (void *cls) /* for postgres_lookup_transfer_summary() */ GNUNET_PQ_make_prepare ("lookup_transfer_summary", "SELECT" - " order_id" - ",exchange_deposit_value" - ",exchange_deposit_fee" - " FROM merchant_transfers" - " JOIN merchant_transfer_to_coin USING (credit_serial)" - " JOIN merchant_deposits USING (deposit_serial)" - " JOIN merchant_contract_terms USING (order_serial)" - " WHERE wtid=$2" - " AND merchant_transfers.exchange_url=$1"), + " mct.order_id" + ",mtc.exchange_deposit_value" + ",mtc.exchange_deposit_fee" + " FROM merchant_transfers mtr" + " JOIN merchant_transfer_to_coin mtc" + " USING (credit_serial)" + " JOIN merchant_deposits dep" + " USING (deposit_serial)" + " JOIN merchant_deposit_confirmations mcon" + " USING (deposit_confirmation_serial)" + " JOIN merchant_contract_terms mct" + " USING (order_serial)" + " WHERE mtr.wtid=$2" + " AND mtr.exchange_url=$1"), /* for postgres_lookup_transfer_details() */ GNUNET_PQ_make_prepare ("lookup_transfer_details", "SELECT" - " merchant_contract_terms.h_contract_terms" - ",merchant_transfer_to_coin.offset_in_exchange_list" - ",merchant_deposits.coin_pub" - ",exchange_deposit_value" - ",exchange_deposit_fee" - " FROM merchant_transfer_to_coin" - " JOIN merchant_deposits USING (deposit_serial)" - " JOIN merchant_contract_terms USING (order_serial)" - " JOIN merchant_transfers USING (credit_serial)" - " WHERE merchant_transfers.wtid=$2" - " AND merchant_transfers.exchange_url=$1"), + " mterm.h_contract_terms" + ",mtcoin.offset_in_exchange_list" + ",dep.coin_pub" + ",mtcoin.exchange_deposit_value" + ",mtcoin.exchange_deposit_fee" + " FROM merchant_transfer_to_coin mtcoin" + " JOIN merchant_deposits dep" + " USING (deposit_serial)" + " JOIN merchant_deposit_confirmations mcon" + " USING (deposit_confirmation_serial)" + " JOIN merchant_contract_terms mterm" + " USING (order_serial)" + " JOIN merchant_transfers mtr" + " USING (credit_serial)" + " WHERE mtr.wtid=$2" + " AND mtr.exchange_url=$1"), /* For postgres_insert_reserve() */ GNUNET_PQ_make_prepare ("insert_reserve_key", "INSERT INTO merchant_reward_reserve_keys" @@ -3786,6 +3815,8 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) = &TMH_PG_lookup_deposits; plugin->insert_exchange_signkey = &TMH_PG_insert_exchange_signkey; + plugin->insert_deposit_confirmation + = &TMH_PG_insert_deposit_confirmation; plugin->insert_deposit = &TMH_PG_insert_deposit; plugin->lookup_refunds diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c index 4c2ef5c9..94f47f70 100644 --- a/src/backenddb/test_merchantdb.c +++ b/src/backenddb/test_merchantdb.c @@ -304,9 +304,6 @@ lookup_instances_cb (void *cls, } - - - /** * Tests @e insert_instance. * @@ -2359,6 +2356,11 @@ struct DepositData struct TALER_CoinSpendPublicKeyP coin_pub; /** + * Signature of the coin that has been deposited. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** * URL of the exchange. */ const char *exchange_url; @@ -2397,39 +2399,6 @@ struct DepositData /** - * Private key for my_sign_cb(). - */ -static const struct TALER_ExchangePrivateKeyP *msc_exchange_priv; - -/** - * Function that signs the message in @a purpose with the - * exchange's signing key from #msc_exchange_priv. - * - * The @a purpose data is the beginning of the data of which the signature is - * to be created. The `size` field in @a purpose must correctly indicate the - * number of bytes of the data structure, including its header. * - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the exchange - * @param[out] sig signature over purpose using current signing key - * @return #TALER_EC_NONE on success - */ -static enum TALER_ErrorCode -my_sign_cb ( - const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct TALER_ExchangePublicKeyP *pub, - struct TALER_ExchangeSignatureP *sig) -{ - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign_ (&msc_exchange_priv->eddsa_priv, - purpose, - &sig->eddsa_signature)); - GNUNET_CRYPTO_eddsa_key_get_public (&msc_exchange_priv->eddsa_priv, - &pub->eddsa_pub); - return TALER_EC_NONE; -} - - -/** * Generates deposit data for an order. * * @param instance the instance to make the deposit to. @@ -2448,7 +2417,6 @@ make_deposit (const struct InstanceData *instance, struct TALER_CoinSpendPrivateKeyP coin_priv; struct GNUNET_TIME_Timestamp now; struct TALER_Amount amount_without_fee; - struct TALER_ExchangePublicKeyP exchange_pub; now = GNUNET_TIME_timestamp_get (); deposit->timestamp = now; @@ -2476,22 +2444,12 @@ make_deposit (const struct InstanceData *instance, &deposit->amount_with_fee, &deposit->deposit_fee)); deposit->h_wire = account->h_wire; - msc_exchange_priv = &signkey->exchange_priv; - GNUNET_assert (TALER_EC_NONE == - TALER_exchange_online_deposit_confirmation_sign ( - &my_sign_cb, - &deposit->h_contract_terms, - &deposit->h_wire, - NULL, - now, - now, - now, - &amount_without_fee, - &deposit->coin_pub, - &instance->merchant_pub, - &exchange_pub, - &deposit->exchange_sig)); - msc_exchange_priv = NULL; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &deposit->exchange_sig, + sizeof (deposit->exchange_sig)); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &deposit->coin_sig, + sizeof (deposit->coin_sig)); } @@ -2534,21 +2492,38 @@ test_insert_deposit (const struct InstanceData *instance, const struct DepositData *deposit, enum GNUNET_DB_QueryStatus expected_result) { - TEST_COND_RET_ON_FAIL (expected_result == - plugin->insert_deposit (plugin->cls, - instance->instance.id, - deposit->timestamp, - &deposit->h_contract_terms, - &deposit->coin_pub, - deposit->exchange_url, - &deposit->amount_with_fee, - &deposit->deposit_fee, - &deposit->refund_fee, - &deposit->wire_fee, - &deposit->h_wire, - &deposit->exchange_sig, - &signkey->exchange_pub), - "Insert deposit failed\n"); + uint64_t row; + struct TALER_Amount awf; + + GNUNET_assert (0 <= + TALER_amount_subtract (&awf, + &deposit->amount_with_fee, + &deposit->deposit_fee)); + TEST_COND_RET_ON_FAIL ( + expected_result == + plugin->insert_deposit_confirmation (plugin->cls, + instance->instance.id, + deposit->timestamp, + &deposit->h_contract_terms, + deposit->exchange_url, + &awf, + &deposit->wire_fee, + &deposit->h_wire, + &deposit->exchange_sig, + &signkey->exchange_pub, + &row), + "Insert deposit confirmation failed\n"); + TEST_COND_RET_ON_FAIL ( + expected_result == + plugin->insert_deposit (plugin->cls, + 0, + row, + &deposit->coin_pub, + &deposit->coin_sig, + &deposit->amount_with_fee, + &deposit->deposit_fee, + &deposit->refund_fee), + "Insert deposit failed\n"); return 0; } @@ -2588,7 +2563,6 @@ struct TestLookupDeposits_Closure * @param amount_with_fee amount of the deposit with fees. * @param deposit_fee fee charged for the deposit. * @param refund_fee fee charged in case of a refund. - * @param wire_fee fee charged when the money is wired. */ static void lookup_deposits_cb (void *cls, @@ -2596,8 +2570,7 @@ lookup_deposits_cb (void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee) + const struct TALER_Amount *refund_fee) { struct TestLookupDeposits_Closure *cmp = cls; if (NULL == cmp) @@ -2625,14 +2598,7 @@ lookup_deposits_cb (void *cls, refund_fee)) && (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].refund_fee, - refund_fee)) && - (GNUNET_OK == - TALER_amount_cmp_currency ( - &cmp->deposits_to_cmp[i].wire_fee, - wire_fee)) && - (0 == - TALER_amount_cmp (&cmp->deposits_to_cmp[i].wire_fee, - wire_fee))) + refund_fee))) { cmp->results_matching[i] += 1; } diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h index fb05bf1c..fd29edba 100644 --- a/src/include/taler_merchantdb_plugin.h +++ b/src/include/taler_merchantdb_plugin.h @@ -370,7 +370,7 @@ struct TALER_MERCHANTDB_TemplateDetails * In this template contract, we can have additional information. */ json_t *template_contract; - + /** * ID of the OTP device linked to the template, or NULL. */ @@ -606,7 +606,6 @@ typedef void * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin * @param refund_fee fee the exchange will charge for refunding this coin - * @param wire_fee wire fee the exchange charges */ typedef void (*TALER_MERCHANTDB_DepositsCallback)( @@ -615,8 +614,7 @@ typedef void const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee); + const struct TALER_Amount *refund_fee); /** @@ -1348,7 +1346,7 @@ struct TALER_MERCHANTDB_Plugin const struct TALER_MerchantWireHashP *h_wire, const char *credit_facade_url, const json_t *credit_facade_credentials); - + /** * Obtain information about an instance's accounts. @@ -1384,15 +1382,15 @@ struct TALER_MERCHANTDB_Plugin struct TALER_MERCHANTDB_AccountDetails *ad); - /** - * Obtain detailed information about an instance's account. - * - * @param cls closure - * @param id identifier of the instance - * @param payto_uri URI of the account - * @param[out] ad account details returned - * @return database result code - */ + /** + * Obtain detailed information about an instance's account. + * + * @param cls closure + * @param id identifier of the instance + * @param payto_uri URI of the account + * @param[out] ad account details returned + * @return database result code + */ enum GNUNET_DB_QueryStatus (*select_account_by_uri)( void *cls, @@ -1944,36 +1942,60 @@ struct TALER_MERCHANTDB_Plugin /** - * Insert payment confirmation from the exchange into the database. + * Insert deposit confirmation from the exchange into the database. * * @param cls closure * @param instance_id instance to lookup deposits for * @param deposit_timestamp time when the exchange generated the deposit confirmation * @param h_contract_terms proposal data's hashcode - * @param coin_pub public key of the coin * @param exchange_url URL of the exchange that issued @a coin_pub - * @param amount_with_fee amount the exchange will deposit for this coin - * @param deposit_fee fee the exchange will charge for this coin + * @param total_without_fees deposited total in the batch without fees * @param wire_fee wire fee the exchange charges * @param h_wire hash of the wire details of the target account of the merchant * @param exchange_sig signature from exchange that coin was accepted * @param exchange_pub signing key that was used for @a exchange_sig + * @param[out] batch_deposit_serial_id set to the table row * @return transaction status */ enum GNUNET_DB_QueryStatus - (*insert_deposit)(void *cls, - const char *instance_id, - struct GNUNET_TIME_Timestamp deposit_timestamp, - const struct TALER_PrivateContractHashP *h_contract_terms, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const char *exchange_url, - const struct TALER_Amount *amount_with_fee, - const struct TALER_Amount *deposit_fee, - const struct TALER_Amount *refund_fee, - const struct TALER_Amount *wire_fee, - const struct TALER_MerchantWireHashP *h_wire, - const struct TALER_ExchangeSignatureP *exchange_sig, - const struct TALER_ExchangePublicKeyP *exchange_pub); + (*insert_deposit_confirmation)( + void *cls, + const char *instance_id, + struct GNUNET_TIME_Timestamp deposit_timestamp, + const struct TALER_PrivateContractHashP *h_contract_terms, + const char *exchange_url, + const struct TALER_Amount *total_without_fees, + const struct TALER_Amount *wire_fee, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_ExchangeSignatureP *exchange_sig, + const struct TALER_ExchangePublicKeyP *exchange_pub, + uint64_t *batch_deposit_serial_id); + + + /** + * Insert information about coin deposited as part of + * a batch into the database. + * + * @param cls closure + * @param offset offset of the coin in the batch + * @param deposit_confirmation_serial_id deposit confirmation for the batch the coin is part of + * @param coin_pub public key of the coin + * @param coin_sig deposit signature of the coin + * @param amount_with_fee amount the exchange will deposit for this coin + * @param deposit_fee fee the exchange will charge for this coin + * @param refund_fee fee the exchange will charge for refunds of coin + * @return transaction status + */ + enum GNUNET_DB_QueryStatus + (*insert_deposit)( + void *cls, + uint32_t offset, + uint64_t deposit_confirmation_serial_id, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig, + const struct TALER_Amount *amount_with_fee, + const struct TALER_Amount *deposit_fee, + const struct TALER_Amount *refund_fee); /** @@ -3057,9 +3079,9 @@ struct TALER_MERCHANTDB_Plugin * if template unknown. */ enum GNUNET_DB_QueryStatus - (*delete_otp) (void *cls, - const char *instance_id, - const char *otp_id); + (*delete_otp)(void *cls, + const char *instance_id, + const char *otp_id); /** * Insert details about a particular OTP device. @@ -3071,10 +3093,10 @@ struct TALER_MERCHANTDB_Plugin * @return database result code */ enum GNUNET_DB_QueryStatus - (*insert_otp) (void *cls, - const char *instance_id, - const char *otp_id, - const struct TALER_MERCHANTDB_OtpDeviceDetails *td); + (*insert_otp)(void *cls, + const char *instance_id, + const char *otp_id, + const struct TALER_MERCHANTDB_OtpDeviceDetails *td); /** @@ -3089,10 +3111,10 @@ struct TALER_MERCHANTDB_Plugin * does not yet exist. */ enum GNUNET_DB_QueryStatus - (*update_otp) (void *cls, - const char *instance_id, - const char *otp_id, - const struct TALER_MERCHANTDB_OtpDeviceDetails *td); + (*update_otp)(void *cls, + const char *instance_id, + const char *otp_id, + const struct TALER_MERCHANTDB_OtpDeviceDetails *td); /** * Lookup all of the OTP devices the given instance has configured. @@ -3104,10 +3126,10 @@ struct TALER_MERCHANTDB_Plugin * @return database result code */ enum GNUNET_DB_QueryStatus - (*lookup_otp_devices) (void *cls, - const char *instance_id, - TALER_MERCHANTDB_OtpDeviceCallback cb, - void *cb_cls); + (*lookup_otp_devices)(void *cls, + const char *instance_id, + TALER_MERCHANTDB_OtpDeviceCallback cb, + void *cb_cls); /** @@ -3121,10 +3143,10 @@ struct TALER_MERCHANTDB_Plugin * @return database result code */ enum GNUNET_DB_QueryStatus - (*select_otp) (void *cls, - const char *instance_id, - const char *otp_id, - struct TALER_MERCHANTDB_OtpDeviceDetails *td); + (*select_otp)(void *cls, + const char *instance_id, + const char *otp_id, + struct TALER_MERCHANTDB_OtpDeviceDetails *td); /** @@ -3136,12 +3158,12 @@ struct TALER_MERCHANTDB_Plugin * @param[out] serial set to the OTP device serial number * @return database result code */ enum GNUNET_DB_QueryStatus - (*select_otp_serial) (void *cls, - const char *instance_id, - const char *otp_id, - uint64_t *serial); + (*select_otp_serial)(void *cls, + const char *instance_id, + const char *otp_id, + uint64_t *serial); + - /** * Update details about a particular template. * diff --git a/src/testing/test_merchant_transfer_tracking.sh b/src/testing/test_merchant_transfer_tracking.sh index dfd5f5d2..0e999f25 100755 --- a/src/testing/test_merchant_transfer_tracking.sh +++ b/src/testing/test_merchant_transfer_tracking.sh @@ -245,10 +245,6 @@ taler-exchange-aggregator -y -c $CONF -T ${TO_SLEEP}000000 -t -L INFO &> aggrega taler-exchange-transfer -c $CONF -t -L INFO &> transfer.log echo " DONE" -echo -n "waiting for Nexus and Sandbox to settle the payment .." -sleep 3 -echo " DONE" - echo -n "Obtaining wire transfer details from bank..." if [ 1 = "$USE_FAKEBANK" ] @@ -260,6 +256,9 @@ then TARGET_PAYTO=$(echo "$BANKDATA" | jq -r .outgoing_transactions[0].credit_account) TARGET=$(echo "$TARGET_PAYTO" | awk -F = '{print $2}') else + echo -n "waiting for Nexus and Sandbox to settle the payment .." + sleep 3 + echo " DONE" # Emulating the previous pybank-based logic of getting # the wire transfer information _via the exchange_ bank # account. NOTE: grabbing tx == 0, since the latest |