/*
  This file is part of TALER
  Copyright (C) 2014-2020 Taler Systems SA

  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU General Public License as published by the Free Software
  Foundation; either version 3, or (at your option) any later version.

  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file include/exchangedb_lib.h
 * @brief IO operations for the exchange's private keys
 * @author Florian Dold
 * @author Benedikt Mueller
 * @author Christian Grothoff
 */
#ifndef TALER_EXCHANGEDB_LIB_H
#define TALER_EXCHANGEDB_LIB_H

#include <taler/taler_signatures.h>
#include <taler/taler_bank_service.h>
#include <taler/taler_kyclogic_lib.h>
#include <taler/taler_util.h>


/**
 * Detailed status for persisting an AML program result.
 */
enum TALER_EXCHANGEDB_PersistProgramResultStatus
{
  TALER_EXCHANGEDB_PPRS_OK = 0,
  TALER_EXCHANGEDB_PPRS_BAD_OUTCOME = 1,
};


/**
 * Why the aggregator decided against executing a wire transfer it had
 * already computed.  Stored in the @e deferral_reason column of the
 * append-only `aggregation_deferrals` table, which is the exchange's claim
 * to the auditor about money it is holding on to.  Values are part of the
 * replicated database format and must not be renumbered.
 */
enum TALER_EXCHANGEDB_DeferralReason
{

  /**
   * The exchange gave no reason.  Never written; this is what the auditor
   * books a pending transfer under when it finds no `aggregation_deferrals`
   * row for it at all.
   */
  TALER_EXCHANGEDB_DR_NONE = 0,

  /**
   * What was aggregated does not survive the wire fee and the rounding to
   * the smallest unit the wire method supports, so the exchange is waiting
   * for further deposits to the same account to make the transfer worth
   * making.
   */
  TALER_EXCHANGEDB_DR_AMOUNT_TOO_SMALL = 1,

  /**
   * A legitimization requirement against the recipient account is open, so
   * the exchange must not pay out yet.  The measure in question is named by
   * the @e legitimization_requirement_serial_id column.
   */
  TALER_EXCHANGEDB_DR_KYC = 2
};


/**
 * Information about a denomination key.
 */
struct TALER_EXCHANGEDB_DenominationKeyInformation
{

  /**
   * Signature over this struct to affirm the validity of the key.
   */
  struct TALER_MasterSignatureP signature;

  /**
   * Start time of the validity period for this key.
   */
  struct GNUNET_TIME_Timestamp start;

  /**
   * The exchange will sign fresh coins between @e start and this time.
   * @e expire_withdraw will be somewhat larger than @e start to
   * ensure a sufficiently large anonymity set, while also allowing
   * the Exchange to limit the financial damage in case of a key being
   * compromised.  Thus, exchanges with low volume are expected to have a
   * longer withdraw period (@e expire_withdraw - @e start) than exchanges
   * with high transaction volume.  The period may also differ between
   * types of coins.  A exchange may also have a few denomination keys
   * with the same value with overlapping validity periods, to address
   * issues such as clock skew.
   */
  struct GNUNET_TIME_Timestamp expire_withdraw;

  /**
   * Coins signed with the denomination key must be spent or refreshed
   * between @e start and this expiration time.  After this time, the
   * exchange will refuse transactions involving this key as it will
   * "drop" the table with double-spending information (shortly after)
   * this time.  Note that wallets should refresh coins significantly
   * before this time to be on the safe side.  @e expire_deposit must be
   * significantly larger than @e expire_withdraw (by months or even
   * years).
   */
  struct GNUNET_TIME_Timestamp expire_deposit;

  /**
   * When do signatures with this denomination key become invalid?
   * After this point, these signatures cannot be used in (legal)
   * disputes anymore, as the Exchange is then allowed to destroy its side
   * of the evidence.  @e expire_legal is expected to be significantly
   * larger than @e expire_deposit (by a year or more).
   */
  struct GNUNET_TIME_Timestamp expire_legal;

  /**
   * The value of the coins signed with this denomination key.
   */
  struct TALER_Amount value;

  /**
   * Fees for the coin.
   */
  struct TALER_DenomFeeSet fees;

  /**
   * Hash code of the denomination public key. (Used to avoid having
   * the variable-size RSA key in this struct.)
   */
  struct TALER_DenominationHashP denom_hash;

  /**
   * If denomination was setup for age restriction, non-zero age mask.
   * Note that the mask is not part of the signature.
   */
  struct TALER_AgeMask age_mask;
};


GNUNET_NETWORK_STRUCT_BEGIN

/**
 * Events signalling that a coin deposit status
 * changed.
 */
struct TALER_EXCHANGEDB_CoinDepositEventP
{
  /**
   * Of type #TALER_DBEVENT_EXCHANGE_DEPOSIT_STATUS_CHANGED.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Public key of the merchant.
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

};

/**
 * Events signalling a reserve got funding.
 */
struct TALER_EXCHANGEDB_ReserveEventP
{
  /**
   * Of type #TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Public key of the reserve the event is about.
   */
  struct TALER_ReservePublicKeyP reserve_pub;
};


/**
 * Signature of events signalling a purse changed its status.
 */
struct TALER_EXCHANGEDB_PurseEventP
{
  /**
   * Of type #TALER_DBEVENT_EXCHANGE_PURSE_MERGED or
   * #TALER_DBEVENT_EXCHANGE_PURSE_DEPOSITED.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Public key of the purse the event is about.
   */
  struct TALER_PurseContractPublicKeyP purse_pub;
};


/**
 * Signature of events signalling a KYC process was completed.
 */
struct TALER_EXCHANGEDB_KycCompletedEventP
{
  /**
   * Of type #TALER_DBEVENT_EXCHANGE_KYC_COMPLETED.
   */
  struct GNUNET_DB_EventHeaderP header;

  /**
   * Hash of payto://-URI for which the KYC state changed.
   */
  struct TALER_NormalizedPaytoHashP h_payto;
};


GNUNET_NETWORK_STRUCT_END

/**
 * Meta data about an exchange online signing key.
 */
struct TALER_EXCHANGEDB_SignkeyMetaData
{
  /**
   * Start time of the validity period for this key.
   */
  struct GNUNET_TIME_Timestamp start;

  /**
   * The exchange will sign messages with this key between @e start and this time.
   */
  struct GNUNET_TIME_Timestamp expire_sign;

  /**
   * When do signatures with this sign key become invalid?
   * After this point, these signatures cannot be used in (legal)
   * disputes anymore, as the Exchange is then allowed to destroy its side
   * of the evidence.  @e expire_legal is expected to be significantly
   * larger than @e expire_sign (by a year or more).
   */
  struct GNUNET_TIME_Timestamp expire_legal;

};


/**
 * @brief All information about a denomination key (which is used to
 * sign coins into existence).
 */
struct TALER_EXCHANGEDB_DenominationKey
{
  /**
   * The private key of the denomination.  Will be NULL if the private
   * key is not available (this is the case after the key has expired
   * for signing coins, but is still valid for depositing coins).
   */
  struct TALER_DenominationPrivateKey denom_priv;

  /**
   * Decoded denomination public key (the hash of it is in
   * @e issue, but we sometimes need the full public key as well).
   */
  struct TALER_DenominationPublicKey denom_pub;

  /**
   * Signed public information about a denomination key.
   */
  struct TALER_EXCHANGEDB_DenominationKeyInformation issue;
};


/**
 * @brief A summary of a Reserve
 */
struct TALER_EXCHANGEDB_Reserve
{
  /**
   * The reserve's public key.  This uniquely identifies the reserve
   */
  struct TALER_ReservePublicKeyP pub;

  /**
   * The balance amount existing in the reserve
   */
  struct TALER_Amount balance;

  /**
   * The expiration date of this reserve; funds will be wired back
   * at this time.
   */
  struct GNUNET_TIME_Timestamp expiry;

  /**
   * The legal expiration date of this reserve; we will forget about
   * it at this time.
   */
  struct GNUNET_TIME_Timestamp gc;
};


/**
 * Public key to which a nonce is locked.
 */
union TALER_EXCHANGEDB_NonceLockTargetP
{
  /**
   * Nonce is locked to this coin key.
   */
  struct TALER_CoinSpendPublicKeyP coin;

  /**
   * Nonce is locked to this reserve key.
   */
  struct TALER_ReservePublicKeyP reserve;
};


/**
 * @brief Data about a coin for a deposit operation.
 */
struct TALER_EXCHANGEDB_CoinDepositInformation
{
  /**
   * Information about the coin that is being deposited.
   */
  struct TALER_CoinPublicInfo coin;

  /**
   * ECDSA signature affirming that the customer intends
   * this coin to be deposited at the merchant identified
   * by @e h_wire in relation to the proposal data identified
   * by @e h_contract_terms.
   */
  struct TALER_CoinSpendSignatureP csig;

  /**
   * Fraction of the coin's remaining value to be deposited, including
   * depositing fee (if any).  The coin is identified by @e coin_pub.
   */
  struct TALER_Amount amount_with_fee;

};


/**
 * @brief Data from a batch deposit operation.
 */
struct TALER_EXCHANGEDB_BatchDeposit
{

  /**
   * Public key of the merchant.  Enables later identification
   * of the merchant in case of a need to rollback transactions.
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Signature of the merchant over the contract, of purpose
   * #TALER_SIGNATURE_MERCHANT_CONTRACT.
   */
  struct TALER_MerchantSignatureP merchant_sig;

  /**
   * Hash over the proposal data between merchant and customer
   * (remains unknown to the Exchange).
   */
  struct TALER_PrivateContractHashP h_contract_terms;

  /**
   * Hash over additional inputs by the wallet.
   */
  struct GNUNET_HashCode wallet_data_hash;

  /**
   * Unsalted hash over @e receiver_wire_account.
   */
  struct TALER_FullPaytoHashP wire_target_h_payto;

  /**
   * Salt used by the merchant to compute "h_wire".
   */
  struct TALER_WireSaltP wire_salt;

  /**
   * Time when this request was generated.  Used, for example, to
   * assess when (roughly) the income was achieved for tax purposes.
   * Note that the Exchange will only check that the timestamp is not "too
   * far" into the future (i.e. several days).  The fact that the
   * timestamp falls within the validity period of the coin's
   * denomination key is irrelevant for the validity of the deposit
   * request, as obviously the customer and merchant could conspire to
   * set any timestamp.  Also, the Exchange must accept very old deposit
   * requests, as the merchant might have been unable to transmit the
   * deposit request in a timely fashion (so back-dating is not
   * prevented).
   */
  struct GNUNET_TIME_Timestamp wallet_timestamp;

  /**
   * How much time does the merchant have to issue a refund request?
   * Zero if refunds are not allowed.  After this time, the coin
   * cannot be refunded.
   */
  struct GNUNET_TIME_Timestamp refund_deadline;

  /**
   * How much time does the merchant have to execute the wire transfer?
   * This time is advisory for aggregating transactions, not a hard
   * constraint (as the merchant can theoretically pick any time,
   * including one in the past).
   */
  struct GNUNET_TIME_Timestamp wire_deadline;

  /**
   * Row ID of the policy details; 0 if no policy applies.
   */
  uint64_t policy_details_serial_id;

  /**
   * Information about the receiver for executing the transaction.  URI in
   * payto://-format.
   */
  struct TALER_FullPayto receiver_wire_account;

  /**
   * Optional extra information to include in the wire transfer
   * subject.
   */
  const char *extra_wire_subject_metadata;

  /**
   * Array about the coins that are being deposited.
   */
  const struct TALER_EXCHANGEDB_CoinDepositInformation *cdis;

  /**
   * Length of the @e cdis array.
   */
  unsigned int num_cdis;

  /**
   * False if @e wallet_data_hash was provided
   */
  bool no_wallet_data_hash;

  /**
   * True if further processing is blocked by policy.
   */
  bool policy_blocked;

};


/**
 * @brief Data from a deposit operation.  The combination of
 * the coin's public key, the merchant's public key and the
 * transaction ID must be unique.  While a coin can (theoretically) be
 * deposited at the same merchant twice (with partial spending), the
 * merchant must either use a different public key or a different
 * transaction ID for the two transactions.  The same coin must not
 * be used twice at the same merchant for the same transaction
 * (as determined by transaction ID).
 */
struct TALER_EXCHANGEDB_Deposit
{
  /**
   * Information about the coin that is being deposited.
   */
  struct TALER_CoinPublicInfo coin;

  /**
   * ECDSA signature affirming that the customer intends
   * this coin to be deposited at the merchant identified
   * by @e h_wire in relation to the proposal data identified
   * by @e h_contract_terms.
   */
  struct TALER_CoinSpendSignatureP csig;

  /**
   * Public key of the merchant.  Enables later identification
   * of the merchant in case of a need to rollback transactions.
   */
  struct TALER_MerchantPublicKeyP merchant_pub;

  /**
   * Hash over the proposal data between merchant and customer
   * (remains unknown to the Exchange).
   */
  struct TALER_PrivateContractHashP h_contract_terms;

  /**
   * Salt used by the merchant to compute "h_wire".
   */
  struct TALER_WireSaltP wire_salt;

  /**
   * Hash over inputs from the wallet to customize the contract.
   */
  struct GNUNET_HashCode wallet_data_hash;

  /**
   * Hash over the policy data for this deposit (remains unknown to the
   * Exchange).  Needed for the verification of the deposit's signature
   */
  struct TALER_ExtensionPolicyHashP h_policy;

  /**
   * Time when this request was generated.  Used, for example, to
   * assess when (roughly) the income was achieved for tax purposes.
   * Note that the Exchange will only check that the timestamp is not "too
   * far" into the future (i.e. several days).  The fact that the
   * timestamp falls within the validity period of the coin's
   * denomination key is irrelevant for the validity of the deposit
   * request, as obviously the customer and merchant could conspire to
   * set any timestamp.  Also, the Exchange must accept very old deposit
   * requests, as the merchant might have been unable to transmit the
   * deposit request in a timely fashion (so back-dating is not
   * prevented).
   */
  struct GNUNET_TIME_Timestamp timestamp;

  /**
   * How much time does the merchant have to issue a refund request?
   * Zero if refunds are not allowed.  After this time, the coin
   * cannot be refunded.
   */
  struct GNUNET_TIME_Timestamp refund_deadline;

  /**
   * How much time does the merchant have to execute the wire transfer?
   * This time is advisory for aggregating transactions, not a hard
   * constraint (as the merchant can theoretically pick any time,
   * including one in the past).
   */
  struct GNUNET_TIME_Timestamp wire_deadline;

  /**
   * Fraction of the coin's remaining value to be deposited, including
   * depositing fee (if any).  The coin is identified by @e coin_pub.
   */
  struct TALER_Amount amount_with_fee;

  /**
   * Depositing fee.
   */
  struct TALER_Amount deposit_fee;

  /**
   * Information about the receiver for executing the transaction.  URI in
   * payto://-format.
   */
  struct TALER_FullPayto receiver_wire_account;

  /**
   * True if @e policy_json was provided
   */
  bool has_policy;

  /**
   * True if @e wallet_data_hash is not in use.
   */
  bool no_wallet_data_hash;

};


/**
 * @brief Specification for coin in a melt operation.
 */
struct TALER_EXCHANGEDB_Refresh
{
  /**
   * Information about the coin that is being melted.
   */
  struct TALER_CoinPublicInfo coin;

  /**
   * Signature over the melting operation.
   */
  struct TALER_CoinSpendSignatureP coin_sig;

  /**
   * Refresh commitment this coin is melted into.
   */
  struct TALER_RefreshCommitmentP rc;

  /**
   * How much value is being melted?  This amount includes the fees,
   * so the final amount contributed to the melt is this value minus
   * the fee for melting the coin.  We include the fee in what is
   * being signed so that we can verify a reserve's remaining total
   * balance without needing to access the respective denomination key
   * information each time.
   */
  struct TALER_Amount amount_with_fee;

  /**
   * Index (smaller #TALER_CNC_KAPPA) which the exchange has chosen to not
   * have revealed during cut and choose.
   */
  uint32_t noreveal_index;

};


/**
 * Information about a /purses/$PID/deposit operation.
 */
struct TALER_EXCHANGEDB_PurseDeposit
{

  /**
   * Exchange hosting the purse, NULL for this exchange.
   */
  char *exchange_base_url;

  /**
   * Public key of the purse.
   */
  struct TALER_PurseContractPublicKeyP purse_pub;

  /**
   * Contribution of the coin to the purse, including
   * deposit fee.
   */
  struct TALER_Amount amount;

  /**
   * Depositing fee.
   */
  struct TALER_Amount deposit_fee;

  /**
   * Signature by the coin affirming the deposit.
   */
  struct TALER_CoinSpendSignatureP coin_sig;

  /**
   * Public key of the coin.
   */
  struct TALER_CoinSpendPublicKeyP coin_pub;

  /**
   * Hash of the age commitment used to sign the coin, if age restriction was
   * applicable to the denomination.  May be all zeroes if no age restriction
   * applies.
   */
  struct TALER_AgeCommitmentHashP h_age_commitment;

  /**
   * Set to true if @e h_age_commitment is not available.
   */
  bool no_age_commitment;

};


/**
 * Information about a melt operation since vDOLDPLUS of the protocol.
 * This also includes the information for the reveal phase.
 */
struct TALER_EXCHANGEDB_Refresh_vDOLDPLUS
{
  /**
   * Information about the coin that is being melted.
   */
  struct TALER_CoinPublicInfo coin;

  /**
   * Signature over the melting operation.
   */
  struct TALER_CoinSpendSignatureP coin_sig;

  /**
   * Refresh commitment this coin is melted into.
   */
  struct TALER_RefreshCommitmentP rc;

  /**
   * True if the client has successfully performed the reveal part
   * of the refresh protocol, after the melt.
   */
  bool is_revealed;

  /**
   * @since vDOLDPLUS
   * Mark if we have a v27 Refresh object.
   * That is, the @a refresh_seed refers to the vDOLDPLUS master_refresh_seed
   * from the original request, AND the client has provided transfer public keys,
   * see below, @a transfer_public_keys
   */
  bool is_v27_refresh;

  /**
   * Public seed from which the refresh nonces (v27) or transfer secrets (vDOLDPLUS)
   * per coin candidate were derived from.
   */
  struct TALER_PublicRefreshMasterSeedP refresh_seed;

  /**
   * How much value is being melted?  This amount includes the fees,
   * so the final amount contributed to the melt is this value minus
   * the fee for melting the coin.  We include the fee in what is
   * being signed so that we can verify a reserve's remaining total
   * balance without needing to access the respective denomination key
   * information each time.
   */
  struct TALER_Amount amount_with_fee;

  /**
   * Number of coins to be refreshed into
   */
  size_t num_coins;

  /**
   * The running hash over all  kappa * @a num_coins blinded coin envelopes, provided by
   * the client.
   */
  struct TALER_HashBlindedPlanchetsP planchets_h;

  /**
   * The running hash over all chosen (noreveal_index) @a num_coins blinded coin envelopes.
   */
  struct TALER_HashBlindedPlanchetsP selected_h;

  /**
   * Array of @a num_coins denomination signatures of the blinded coins.
   */
  struct TALER_BlindedDenominationSignature *denom_sigs;

  /**
   * If @a is_v27_refresh is false, the client performed a vDOLDPLUS refresh,
   * and has provided @a num_coins * kappa transfer public keys.
   * This is the chosen (at index @a noreveal_index) array of @a num_coins transfer public keys.
   */
  struct TALER_TransferPublicKeyP *transfer_pubs;

  /**
   * Array of @a num_coins serial id's of the denominations.
   * If @e coin.no_age_commitment is false, the denominations
   * MUST support age restriction.
   */
  uint64_t *denom_serials;

  /**
   * Index (smaller #TALER_CNC_KAPPA) which the exchange chose to not
   * to be revealed during cut and choose.
   */
  uint32_t noreveal_index;

  /**
   * True, if the client has successfully performed the reveal step
   */
  bool revealed;

  /**
   * If true, no @e blinding_seed is set and @e num_cs_r_values is 0.
   */
  bool no_blinding_seed;

  /**
   * If @e no_blinding_seed is false, the blinding seed for the nonces needed for
   * blind CS signatures.
   */
  struct TALER_BlindingMasterSeedP blinding_seed;

  /**
   * Number of elements in @e cs_r_values.
   */
  size_t num_cs_r_values;

  /**
   * Array @e num_cs_r_values of public R-values for CS that were generated from the
   * @e blinding_seed, a coin's index and the denomination's private key during the
   * the /melt request, to ensure idempotency in case of expiration of a denomination.
   * NULL if @e num_cs_r_values is 0.
   */
  struct GNUNET_CRYPTO_CSPublicRPairP *cs_r_values;

  /**
   * If @e num_cs_r_values is not 0, the bitvector of choices for the pairs
   * in @e cs_r_values that was made by the exchange.  The vector is in NBO
   * and the lowest bit represents the choice for the pair at index 0 into @e cs_r_values;
   */
  uint64_t cs_r_choices;

  /**
   * [out]-Array of @a num_coins hashes of the public keys of the denominations
   * identified by @e denom_serials.  This field is set when calling
   * get_refresh
   */
  struct TALER_DenominationHashP *denom_pub_hashes;
};


/**
 * Generic KYC status for some operation.
 */
struct TALER_EXCHANGEDB_KycStatus
{

  /**
   * Account public key that is currently associated
   * with the account. Only set if @e have_account_pub
   * is true.
   */
  union TALER_AccountPublicKeyP account_pub;

  /**
   * Number that identifies the KYC requirement the operation
   * was about.
   */
  uint64_t requirement_row;

  /**
   * True if @e account_pub is set.
   */
  bool have_account_pub;

  /**
   * True if the KYC status is "satisfied".
   */
  bool ok;

};


/**
 * Function called with details about incoming wire transfers.
 *
 * @param cls closure
 * @param rowid unique serial ID for the refresh session in our DB
 * @param reserve_pub public key of the reserve (also the wire subject)
 * @param credit amount that was received
 * @param sender_account_details information about the sender's bank account, in payto://-format
 * @param wire_reference unique identifier for the wire transfer
 * @param execution_date when did we receive the funds
 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
 */
#ifndef TALER_EXCHANGEDB_RESERVE_IN_RESULT_CLOSURE
#define TALER_EXCHANGEDB_RESERVE_IN_RESULT_CLOSURE void
#endif
typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_ReserveInCallback)(
  TALER_EXCHANGEDB_RESERVE_IN_RESULT_CLOSURE *cls,
  uint64_t rowid,
  const struct TALER_ReservePublicKeyP *reserve_pub,
  const struct TALER_Amount *credit,
  const struct TALER_FullPayto sender_account_details,
  uint64_t wire_reference,
  struct GNUNET_TIME_Timestamp execution_date);


/**
 * Function called with the results of the lookup of the
 * wire transfer data of the exchange.
 *
 * @param cls closure
 * @param rowid identifier of the respective row in the database
 * @param date timestamp of the wire transfer (roughly)
 * @param wtid wire transfer subject
 * @param payto_uri details of the receiver, URI in payto://-format
 * @param amount amount that was wired
 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
 */
#ifndef TALER_EXCHANGEDB_WIRE_TRANSFER_OUT_RESULT_CLOSURE
#define TALER_EXCHANGEDB_WIRE_TRANSFER_OUT_RESULT_CLOSURE void
#endif
typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_WireTransferOutCallback)(
  TALER_EXCHANGEDB_WIRE_TRANSFER_OUT_RESULT_CLOSURE *cls,
  uint64_t rowid,
  struct GNUNET_TIME_Timestamp date,
  const struct TALER_WireTransferIdentifierRawP *wtid,
  const struct TALER_FullPayto payto_uri,
  const struct TALER_Amount *amount);


/**
 * Function called with details about expired reserves.
 *
 * @param cls closure
 * @param reserve_pub public key of the reserve
 * @param left amount left in the reserve
 * @param account_details information about the reserve's bank account, in payto://-format
 * @param expiration_date when did the reserve expire
 * @param close_request_row row that caused the reserve
 *        to be closed, 0 if it expired without request
 * @return #GNUNET_OK on success,
 *         #GNUNET_NO to retry
 *         #GNUNET_SYSERR on hard failures (exit)
 */
#ifndef TALER_EXCHANGEDB_RESERVE_EXPIRED_RESULT_CLOSURE
#define TALER_EXCHANGEDB_RESERVE_EXPIRED_RESULT_CLOSURE void
#endif
typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_ReserveExpiredCallback)(
  TALER_EXCHANGEDB_RESERVE_EXPIRED_RESULT_CLOSURE *cls,
  const struct TALER_ReservePublicKeyP *reserve_pub,
  const struct TALER_Amount *left,
  const struct TALER_FullPayto account_details,
  struct GNUNET_TIME_Timestamp expiration_date,
  uint64_t close_request_row);


/**
 * Callback that is given AML-relevant transfer data.
 *
 * @param cls closure
 * @param row_id current row in AML status table
 * @param payto_uri account involved with the wire transfer
 * @param execution_time when was the transfer made
 * @param amount wire amount of the transfer
 */
#ifndef TALER_EXCHANGEDB_AML_TRANSFER_RESULT_CLOSURE
#define TALER_EXCHANGEDB_AML_TRANSFER_RESULT_CLOSURE void
#endif
typedef void
(*TALER_EXCHANGEDB_AmlTransferCallback)(
  TALER_EXCHANGEDB_AML_TRANSFER_RESULT_CLOSURE *cls,
  uint64_t row_id,
  const char *payto_uri,
  struct GNUNET_TIME_Absolute execution_time,
  const struct TALER_Amount *amount);


/**
 * Initialize the database connection.
 *
 * @param cfg configuration to use
 * @return NULL on failure
 */
struct TALER_EXCHANGEDB_PostgresContext *
TALER_EXCHANGEDB_connect (
  const struct GNUNET_CONFIGURATION_Handle *cfg);


/**
 * Initialize the database connection for administration.
 * Disables the check that the database schema is current.
 *
 * @param cfg configuration to use
 * @return NULL on failure
 */
struct TALER_EXCHANGEDB_PostgresContext *
TALER_EXCHANGEDB_connect_admin (
  const struct GNUNET_CONFIGURATION_Handle *cfg);


/**
 * Shutdown the database connection.
 *
 * @param[in] pg connection to drop
 */
void
TALER_EXCHANGEDB_disconnect (struct TALER_EXCHANGEDB_PostgresContext *pg);


/**
 * Meta data about a denomination public key.
 * If this is changed, you must also adjust
 * taler-exchange-httpd-post-management-keys.c::denomination_meta_cmp().
 */
struct TALER_EXCHANGEDB_DenominationKeyMetaData
{
  /**
   * Serial of the denomination key as in the DB.
   * Can be used calls to stored procedures in order to spare
   * additional lookups.
   */
  uint64_t serial;

  /**
   * Start time of the validity period for this key.
   */
  struct GNUNET_TIME_Timestamp start;

  /**
   * The exchange will sign fresh coins between @e start and this time.
   * @e expire_withdraw will be somewhat larger than @e start to
   * ensure a sufficiently large anonymity set, while also allowing
   * the Exchange to limit the financial damage in case of a key being
   * compromised.  Thus, exchanges with low volume are expected to have a
   * longer withdraw period (@e expire_withdraw - @e start) than exchanges
   * with high transaction volume.  The period may also differ between
   * types of coins.  A exchange may also have a few denomination keys
   * with the same value with overlapping validity periods, to address
   * issues such as clock skew.
   */
  struct GNUNET_TIME_Timestamp expire_withdraw;

  /**
   * Coins signed with the denomination key must be spent or refreshed
   * between @e start and this expiration time.  After this time, the
   * exchange will refuse transactions involving this key as it will
   * "drop" the table with double-spending information (shortly after)
   * this time.  Note that wallets should refresh coins significantly
   * before this time to be on the safe side.  @e expire_deposit must be
   * significantly larger than @e expire_withdraw (by months or even
   * years).
   */
  struct GNUNET_TIME_Timestamp expire_deposit;

  /**
   * When do signatures with this denomination key become invalid?
   * After this point, these signatures cannot be used in (legal)
   * disputes anymore, as the Exchange is then allowed to destroy its side
   * of the evidence.  @e expire_legal is expected to be significantly
   * larger than @e expire_deposit (by a year or more).
   */
  struct GNUNET_TIME_Timestamp expire_legal;

  /**
   * The value of the coins signed with this denomination key.
   */
  struct TALER_Amount value;

  /**
   * The fees the exchange charges for operations with
   * coins of this denomination.
   */
  struct TALER_DenomFeeSet fees;

  /**
   * Age restriction for the denomination. (can be zero). If not zero, the bits
   * set in the mask mark the edges at the beginning of a next age group.  F.e.
   * for the age groups
   *     0-7, 8-9, 10-11, 12-14, 14-15, 16-17, 18-21, 21-*
   * the following bits are set:
   *
   *   31     24        16        8         0
   *   |      |         |         |         |
   *   oooooooo  oo1oo1o1  o1o1o1o1  ooooooo1
   *
   * A value of 0 means that the denomination does not support the extension for
   * age-restriction.
   */
  struct TALER_AgeMask age_mask;
};


/**
 * Information about an account from the configuration.
 */
struct TALER_EXCHANGEDB_AccountInfo
{
  /**
   * Authentication data. Only parsed if
   * #TALER_EXCHANGEDB_ALO_AUTHDATA was set.
   */
  const struct TALER_BANK_AuthenticationData *auth;

  /**
   * Section in the configuration file that specifies the
   * account. Must start with "exchange-account-".
   */
  const char *section_name;

  /**
   * Name of the wire method used by this account.
   */
  const char *method;

  /**
   * Full payto://-URI of the account. Do not free(), aliased
   * with the underlying `struct WireAccount`.
   */
  struct TALER_FullPayto payto_uri;

  /**
   * true if this account is enabled to be debited
   * by the taler-exchange-aggregator.
   */
  bool debit_enabled;

  /**
   * true if this account is enabled to be credited by wallets
   * and needs to be watched by the taler-exchange-wirewatch.
   * Also, the account will only be included in /wire if credit
   * is enabled.
   */
  bool credit_enabled;
};


/**
 * Function called with information about a wire account.
 *
 * @param cls closure
 * @param ai account information
 */
#ifndef TALER_EXCHANGEDB_ACCOUNT_RESULT_CLOSURE
#define TALER_EXCHANGEDB_ACCOUNT_RESULT_CLOSURE void
#endif
typedef void
(*TALER_EXCHANGEDB_AccountCallback)(
  TALER_EXCHANGEDB_ACCOUNT_RESULT_CLOSURE *cls,
  const struct TALER_EXCHANGEDB_AccountInfo *ai);


/**
 * Return information about all accounts that
 * were loaded by #TALER_EXCHANGEDB_load_accounts().
 *
 * @param cb callback to invoke
 * @param cb_cls closure for @a cb
 */
void
TALER_EXCHANGEDB_find_accounts (TALER_EXCHANGEDB_AccountCallback cb,
                                TALER_EXCHANGEDB_ACCOUNT_RESULT_CLOSURE *cb_cls)
;


/**
 * Find the wire plugin for the given payto:// URL.
 * Only useful after the accounts have been loaded
 * using #TALER_EXCHANGEDB_load_accounts().
 *
 * @param method wire method we need an account for
 * @return NULL on error
 */
const struct TALER_EXCHANGEDB_AccountInfo *
TALER_EXCHANGEDB_find_account_by_method (const char *method);


/**
 * Find the wire plugin for the given payto:// URL
 * Only useful after the accounts have been loaded
 * using #TALER_EXCHANGEDB_load_accounts().
 *
 * @param url wire address we need an account for
 * @return NULL on error
 */
const struct TALER_EXCHANGEDB_AccountInfo *
TALER_EXCHANGEDB_find_account_by_payto_uri (
  const struct TALER_FullPayto url);


/**
 * Options for #TALER_EXCHANGEDB_load_accounts()
 */
enum TALER_EXCHANGEDB_AccountLoaderOptions
{
  TALER_EXCHANGEDB_ALO_NONE = 0,

  /**
   * Load accounts enabled for DEBITs.
   */
  TALER_EXCHANGEDB_ALO_DEBIT = 1,

  /**
   * Load accounts enabled for CREDITs.
   */
  TALER_EXCHANGEDB_ALO_CREDIT = 2,

  /**
   * Load authentication data from the
   * "taler-accountcredentials-" section
   * to access the account at the bank.
   */
  TALER_EXCHANGEDB_ALO_AUTHDATA = 4
};


/**
 * Load account information op the exchange from @a cfg.
 *
 * @param cfg configuration to load from
 * @param options loader options
 * @return #GNUNET_OK on success, #GNUNET_NO if no accounts are configured
 */
enum GNUNET_GenericReturnValue
TALER_EXCHANGEDB_load_accounts (
  const struct GNUNET_CONFIGURATION_Handle *cfg,
  enum TALER_EXCHANGEDB_AccountLoaderOptions options);


/**
 * Free resources allocated by
 * #TALER_EXCHANGEDB_load_accounts().
 */
void
TALER_EXCHANGEDB_unload_accounts (void);


#endif
