/* This file is part of TALER Copyright (C) 2014-2017 INRIA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TALER; see the file COPYING.GPL. If not, see */ /** * @file include/taler_merchantdb_plugin.h * @brief database access for the merchant * @author Florian Dold * @author Christian Grothoff */ #ifndef TALER_MERCHANTDB_PLUGIN_H #define TALER_MERCHANTDB_PLUGIN_H #include #include #include /** * Handle to interact with the database. */ struct TALER_MERCHANTDB_Plugin; /** * Tipically called by `find_contract_terms_by_date`. * * @param cls closure * @param order_id order id * @param row_id serial numer of the transaction in the table, * @param contract_terms proposal data related to order id */ typedef void (*TALER_MERCHANTDB_ProposalDataCallback)(void *cls, const char *order_id, uint64_t row_id, const json_t *contract_terms); /** * Function called with information about a transaction. * * @param cls closure * @param merchant_pub merchant's public key * @param exchange_uri URI of the exchange * @param h_contract_terms proposal data's hashcode * @param h_wire hash of our wire details * @param timestamp time of the confirmation * @param refund refund deadline * @param total_amount total amount we receive for the contract after fees */ typedef void (*TALER_MERCHANTDB_TransactionCallback)(void *cls, const struct TALER_MerchantPublicKeyP *merchant_pub, const char *exchange_uri, const struct GNUNET_HashCode *h_contract_terms, const struct GNUNET_HashCode *h_wire, struct GNUNET_TIME_Absolute timestamp, struct GNUNET_TIME_Absolute refund, const struct TALER_Amount *total_amount); /** * Function called with information about a coin that was deposited. * * @param cls closure * @param h_contract_terms proposal data's hashcode * @param coin_pub public key of the coin * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin * @param refund_fee fee the exchange will charge for refunding this coin * @param exchange_proof proof from exchange that coin was accepted, * matches the `interface DepositSuccess` of the documentation. */ typedef void (*TALER_MERCHANTDB_CoinDepositCallback)(void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, const struct TALER_Amount *refund_fee, const json_t *exchange_proof); /** * Information about the wire transfer corresponding to * a deposit operation. Note that it is in theory possible * that we have a @a h_contract_terms and @a coin_pub in the * result that do not match a deposit that we know about, * for example because someone else deposited funds into * our account. * * @param cls closure * @param h_contract_terms hashcode of the proposal data * @param coin_pub public key of the coin * @param wtid identifier of the wire transfer in which the exchange * send us the money for the coin deposit * @param execution_time when was the wire transfer executed? * @param exchange_proof proof from exchange about what the deposit was for * NULL if we have not asked for this signature */ typedef void (*TALER_MERCHANTDB_TransferCallback)(void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_WireTransferIdentifierRawP *wtid, struct GNUNET_TIME_Absolute execution_time, const json_t *exchange_proof); /** * Function called with information about a wire transfer identifier. * * @param cls closure * @param proof proof from exchange about what the wire transfer was for */ typedef void (*TALER_MERCHANTDB_ProofCallback)(void *cls, const json_t *proof); /** * Function called with information about a refund. * * @param cls closure * @param coin_pub public coin from which the refund comes from * @param rtransaction_id identificator of the refund * @param reason human-readable explaination of the refund * @param refund_amount refund amount which is being taken from coin_pub * @param refund_fee cost of this refund operation */ typedef void (*TALER_MERCHANTDB_RefundCallback)(void *cls, const struct TALER_CoinSpendPublicKeyP *coin_pub, uint64_t rtransaction_id, const char *reason, const struct TALER_Amount *refund_amount, const struct TALER_Amount *refund_fee); /** * Handle to interact with the database. */ struct TALER_MERCHANTDB_Plugin { /** * Closure for all callbacks. */ void *cls; /** * Name of the library which generated this plugin. Set by the * plugin loader. */ char *library_name; /** * Drop merchant tables. Used for testcases. * * @param cls closure * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ int (*drop_tables) (void *cls); /** * Initialize merchant tables * * @param cls closure * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ int (*initialize) (void *cls); /** * Insert proposal data into db; the routine will internally hash and * insert the proposal data's hashcode into the same row. * * @param cls closure * @param order_id alphanumeric string that uniquely identifies the proposal * @param merchant_pub merchant's public key * @param timestamp timestamp of this proposal data * @param contract_terms proposal data to store * @return transaction status */ enum GNUNET_DB_QueryStatus (*insert_contract_terms) (void *cls, const char *order_id, const struct TALER_MerchantPublicKeyP *merchant_pub, struct GNUNET_TIME_Absolute timestamp, const json_t *contract_terms); /** * Mark contract terms as payed. Needed by /history as only payed * contracts must be shown. NOTE: we can't get the list of (payed) * contracts from the transactions table because it lacks contract_terms * plain JSON. In facts, the protocol doesn't allow to store contract_terms * in transactions table, as /pay handler doesn't receive this data * (only /proposal does). */ enum GNUNET_DB_QueryStatus (*mark_proposal_paid) (void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub); /** * Retrieve proposal data given its order ID. * * @param cls closure * @param[out] contract_terms where to store the result * @param order_id order_id used to lookup. * @param merchant_pub instance's public key. * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_contract_terms) (void *cls, json_t **contract_terms, const char *order_id, const struct TALER_MerchantPublicKeyP *merchant_pub); /** * Retrieve proposal data given its hashcode * * @param cls closure * @param[out] contract_terms where to store the result * @param h_contract_terms hashcode used to lookup. * @param merchant_pub instance's public key. * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_contract_terms_from_hash) (void *cls, json_t **contract_terms, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub); /** * Return proposals whose timestamp are older than `date`. * Among those proposals, only those ones being between the * start-th and (start-nrows)-th record are returned. The rows * are sorted having the youngest first. * * @param cls our plugin handle. * @param date only results older than this date are returned. * @param merchant_pub instance's public key; only rows related to this * instance are returned. * @param start only rows with serial id less than start are returned. * @param nrows only nrows rows are returned. * @param future if set to #GNUNET_YES, retrieves rows younger than `date`. * This is typically used to show live updates on the merchant's backoffice * @param cb function to call with transaction data, can be NULL. * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_contract_terms_by_date_and_range) (void *cls, struct GNUNET_TIME_Absolute date, const struct TALER_MerchantPublicKeyP *merchant_pub, uint64_t start, uint64_t nrows, int future, TALER_MERCHANTDB_ProposalDataCallback cb, void *cb_cls); /** * Lookup for a proposal, respecting the signature used by the * /history's db methods. * * @param cls db plugin handle * @param order_id order id used to search for the proposal data * @param merchant_pub public key of the merchant using this method * @param cb the callback * @param cb_cls closure to pass to @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_contract_terms_history) (void *cls, const char *order_id, const struct TALER_MerchantPublicKeyP *merchant_pub, TALER_MERCHANTDB_ProposalDataCallback cb, void *cb_cls); /** * Return proposals whose timestamp are older than `date`. * The rows are sorted having the youngest first.* * * @param cls our plugin handle. * @param date only results older than this date are returned. * @param merchant_pub instance's public key; only rows related to this * instance are returned. * @param nrows only nrows rows are returned. * @param cb function to call with transaction data, can be NULL. * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_contract_terms_by_date) (void *cls, struct GNUNET_TIME_Absolute date, const struct TALER_MerchantPublicKeyP *merchant_pub, uint64_t nrows, TALER_MERCHANTDB_ProposalDataCallback cb, void *cb_cls); /** * Insert transaction data into the database. * * @param cls closure * @param h_contract_terms proposal data's hashcode * @param merchant_pub merchant's public key * @param exchange_uri URI of the exchange * @param h_wire hash of our wire details * @param timestamp time of the confirmation * @param refund refund deadline * @param total_amount total amount we receive for the contract after fees * @return transaction status */ enum GNUNET_DB_QueryStatus (*store_transaction) (void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub, const char *exchange_uri, const struct GNUNET_HashCode *h_wire, struct GNUNET_TIME_Absolute timestamp, struct GNUNET_TIME_Absolute refund, const struct TALER_Amount *total_amount); /** * Insert payment confirmation from the exchange into the database. * * @param cls closure * @param h_contract_terms proposal data's hashcode * @param merchant_pub merchant's public key * @param coin_pub public key of the coin * @param amount_with_fee amount the exchange will deposit for this coin * @param deposit_fee fee the exchange will charge for this coin * @param signkey_pub public key used by the exchange for @a exchange_proof * @param exchange_proof proof from exchange that coin was accepted * @return transaction status */ enum GNUNET_DB_QueryStatus (*store_deposit) (void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee, const struct TALER_Amount *deposit_fee, const struct TALER_Amount *refund_fee, const struct TALER_ExchangePublicKeyP *signkey_pub, const json_t *exchange_proof); /** * Insert mapping of @a coin_pub and @a h_contract_terms to * corresponding @a wtid. * * @param cls closure * @param h_contract_terms proposal data's hashcode * @param coin_pub public key of the coin * @param wtid identifier of the wire transfer in which the exchange * send us the money for the coin deposit * @return transaction status */ enum GNUNET_DB_QueryStatus (*store_coin_to_transfer) (void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_WireTransferIdentifierRawP *wtid); /** * Insert wire transfer confirmation from the exchange into the database. * * @param cls closure * @param exchange_uri from which exchange did we get the @a exchange_proof * @param wtid identifier of the wire transfer * @param execution_time when was @a wtid executed * @param signkey_pub public key used by the exchange for @a exchange_proof * @param exchange_proof proof from exchange about what the deposit was for * @return transaction status */ enum GNUNET_DB_QueryStatus (*store_transfer_to_proof) (void *cls, const char *exchange_uri, const struct TALER_WireTransferIdentifierRawP *wtid, struct GNUNET_TIME_Absolute execution_time, const struct TALER_ExchangePublicKeyP *signkey_pub, const json_t *exchange_proof); /** * Store information about wire fees charged by an exchange, * including signature (so we have proof). * * @param cls closure * @param exchange_pub public key of the exchange * @param h_wire_method hash of wire method * @param wire_fee wire fee charged * @param closing_fee closing fee charged (irrelevant for us, * but needed to check signature) * @param start_date start of fee being used * @param end_date end of fee being used * @param exchange_sig signature of exchange over fee structure * @return transaction status code */ enum GNUNET_DB_QueryStatus (*store_wire_fee_by_exchange) (void *cls, const struct TALER_MasterPublicKeyP *exchange_pub, const struct GNUNET_HashCode *h_wire_method, const struct TALER_Amount *wire_fee, const struct TALER_Amount *closing_fee, struct GNUNET_TIME_Absolute start_date, struct GNUNET_TIME_Absolute end_date, const struct TALER_MasterSignatureP *exchange_sig); /** * Find information about a transaction. * * @param cls our plugin handle * @param date limit to transactions' age * @param cb function to call with transaction data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_transactions_by_date) (void *cls, struct GNUNET_TIME_Absolute date, TALER_MERCHANTDB_TransactionCallback cb, void *cb_cls); /** * Find information about a transaction. * * @param cls our plugin handle * @param h_contract_terms proposal data's hashcode * @param merchant_pub merchant's public key. * @param cb function to call with transaction data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_transaction) (void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub, TALER_MERCHANTDB_TransactionCallback cb, void *cb_cls); /** * Lookup information about coin payments by proposal data's hashcode. * * @param cls closure * @param h_contract_terms proposal data's hashcode * @param merchant_pub merchant's public key. It's AND'd with @a h_contract_terms * in order to find the result. * @param cb function to call with payment data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_payments) (void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub, TALER_MERCHANTDB_CoinDepositCallback cb, void *cb_cls); /** * Lookup information about coin payments by h_contract_terms and coin. * * @param cls closure * @param h_contract_terms proposal data's hashcode * @param merchant_pub merchant's public key. It's AND'd with @a h_contract_terms * in order to find the result. * @param coin_pub public key to use for the search * @param cb function to call with payment data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_payments_by_hash_and_coin) (void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub, TALER_MERCHANTDB_CoinDepositCallback cb, void *cb_cls); /** * Lookup information about a transfer by @a h_contract_terms. Note * that in theory there could be multiple wire transfers for a * single @a h_contract_terms, as the transaction may have involved * multiple coins and the coins may be spread over different wire * transfers. * * @param cls closure * @param h_contract_terms proposal data's hashcode * @param cb function to call with transfer data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_transfers_by_hash) (void *cls, const struct GNUNET_HashCode *h_contract_terms, TALER_MERCHANTDB_TransferCallback cb, void *cb_cls); /** * Lookup information about a coin deposits by @a wtid. * * @param cls closure * @param wtid wire transfer identifier to find matching transactions for * @param cb function to call with payment data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_deposits_by_wtid) (void *cls, const struct TALER_WireTransferIdentifierRawP *wtid, TALER_MERCHANTDB_CoinDepositCallback cb, void *cb_cls); /** * Lookup proof information about a wire transfer. * * @param cls closure * @param exchange_uri from which exchange are we looking for proof * @param wtid wire transfer identifier for the search * @param cb function to call with proof data * @param cb_cls closure for @a cb * @return transaction status */ enum GNUNET_DB_QueryStatus (*find_proof_by_wtid) (void *cls, const char *exchange_uri, const struct TALER_WireTransferIdentifierRawP *wtid, TALER_MERCHANTDB_ProofCallback cb, void *cb_cls); /** * Obtain information about wire fees charged by an exchange, * including signature (so we have proof). * * @param cls closure * @param exchange_pub public key of the exchange * @param h_wire_method hash of wire method * @param contract_date date of the contract to use for the lookup * @param[out] wire_fee wire fee charged * @param[out] closing_fee closing fee charged (irrelevant for us, * but needed to check signature) * @param[out] start_date start of fee being used * @param[out] end_date end of fee being used * @param[out] exchange_sig signature of exchange over fee structure * @return transaction status code */ enum GNUNET_DB_QueryStatus (*lookup_wire_fee) (void *cls, const struct TALER_MasterPublicKeyP *exchange_pub, const struct GNUNET_HashCode *h_wire_method, struct GNUNET_TIME_Absolute contract_date, struct TALER_Amount *wire_fee, struct TALER_Amount *closing_fee, struct GNUNET_TIME_Absolute *start_date, struct GNUNET_TIME_Absolute *end_date, struct TALER_MasterSignatureP *exchange_sig); /** * Function called when some backoffice staff decides to award or * increase the refund on an existing contract. * * @param cls closure * @param merchant_pub merchant's instance public key * @param h_contract_terms * @param merchant_pub merchant's instance public key * @param refund maximum refund to return to the customer for this contract * @param reason 0-terminated UTF-8 string giving the reason why the customer * got a refund (free form, business-specific) * @return transaction status */ enum GNUNET_DB_QueryStatus (*increase_refund_for_contract)(void *cls, const struct GNUNET_HashCode *h_contract_terms, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_Amount *refund, const char *reason); /** * Obtain refunds associated with a contract. * * @param cls closure, typically a connection to the db * @param merchant_pub public key of the merchant instance * @param h_contract_terms hash code of the contract * @param rc function to call for each coin on which there is a refund * @param rc_cls closure for @a rc * @return transaction status */ enum GNUNET_DB_QueryStatus (*get_refunds_from_contract_terms_hash)(void *cls, const struct TALER_MerchantPublicKeyP *merchant_pub, const struct GNUNET_HashCode *h_contract_terms, TALER_MERCHANTDB_RefundCallback rc, void *rc_cls); /** * Add @a credit to a reserve to be used for tipping. Note that * this function does not actually perform any wire transfers to * credit the reserve, it merely tells the merchant backend that * a reserve was topped up. This has to happen before tips can be * authorized. * * @param cls closure, typically a connection to the db * @param reserve_priv which reserve is topped up or created * @param credit_uuid unique identifier for the credit operation * @param credit how much money was added to the reserve * @param expiration when does the reserve expire? * @return transaction status, usually * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT for success * #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a credit_uuid already known */ enum GNUNET_DB_QueryStatus (*enable_tip_reserve)(void *cls, const struct TALER_ReservePrivateKeyP *reserve_priv, const struct GNUNET_HashCode *credit_uuid, const struct TALER_Amount *credit, struct GNUNET_TIME_Absolute expiration); /** * Authorize a tip over @a amount from reserve @a reserve_priv. Remember * the authorization under @a tip_id for later, together with the * @a justification. * * @param cls closure, typically a connection to the db * @param justification why was the tip approved * @param amount how high is the tip (with fees) * @param reserve_priv which reserve is debited * @param[out] expiration set to when the tip expires * @param[out] tip_id set to the unique ID for the tip * @return transaction status, * #TALER_EC_TIP_AUTHORIZE_RESERVE_EXPIRED if the reserve is known but has expired * #TALER_EC_TIP_AUTHORIZE_RESERVE_UNKNOWN if the reserve is not known * #TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS if the reserve has insufficient funds left * #TALER_EC_TIP_AUTHORIZE_DB_HARD_ERROR on hard DB errors * #TALER_EC_TIP_AUTHORIZE_DB_SOFT_ERROR on soft DB errors (client should retry) * #TALER_EC_NONE upon success */ enum TALER_ErrorCode (*authorize_tip)(void *cls, const char *justification, const struct TALER_Amount *amount, const struct TALER_ReservePrivateKeyP *reserve_priv, struct GNUNET_TIME_Absolute *expiration, struct GNUNET_HashCode *tip_id); /** * Pickup a tip over @a amount using pickup id @a pickup_id. * * @param cls closure, typically a connection to the db * @param amount how high is the amount picked up (with fees) * @param tip_id the unique ID from the tip authorization * @param pickup_id the unique ID identifying the pick up operation * (to allow replays, hash over the coin envelope and denomination key) * @param[out] reserve_priv which reserve key to use to sign * @return taler error code * #TALER_EC_TIP_PICKUP_ID_UNKNOWN if @a tip_id is unknown * #TALER_EC_TIP_PICKUP_NO_FUNDS if @a tip_id has insufficient funds left * #TALER_EC_TIP_PICKUP_DB_ERROR on database errors * #TALER_EC_NONE upon success (@a reserve_priv was set) */ enum TALER_ErrorCode (*pickup_tip)(void *cls, const struct TALER_Amount *amount, const struct GNUNET_HashCode *tip_id, const struct GNUNET_HashCode *pickup_id, struct TALER_ReservePrivateKeyP *reserve_priv); /** * Roll back the current transaction of a database connection. * * @param cls the `struct PostgresClosure` with the plugin-specific state * @return #GNUNET_OK on success */ void (*rollback) (void *cls); /** * Start a transaction. * * @param cls the `struct PostgresClosure` with the plugin-specific state * @return #GNUNET_OK on success */ int (*start) (void *cls); /** * Commit the current transaction of a database connection. * * @param cls the `struct PostgresClosure` with the plugin-specific state * @return transaction status code */ enum GNUNET_DB_QueryStatus (*commit) (void *cls); }; #endif