diff options
Diffstat (limited to 'src/exchangedb')
20 files changed, 1466 insertions, 3016 deletions
diff --git a/src/exchangedb/.gitignore b/src/exchangedb/.gitignore index dd3c5ed1..264217a3 100644 --- a/src/exchangedb/.gitignore +++ b/src/exchangedb/.gitignore @@ -1,17 +1,9 @@ -test-exchangedb-auditors -test-exchangedb-denomkeys -test-exchangedb-fees  test-exchangedb-postgres -test-exchangedb-signkeys -test-perf-taler-exchangedb  bench-db-postgres -shard-drop0001.sqltest-exchangedb-by-j-postgres -test-exchangedb-by-j-postgres -perf-exchangedb-reserves-in-insert-postgres +perf_deposits_get_ready-postgres +perf_get_link_data-postgres +perf_reserves_in_insert-postgres +perf_select_refunds_by_coin-postgres  exchange-0002.sql  procedures.sql  exchange-0003.sql -test-exchangedb-batch-reserves-in-insert-postgres -test-exchangedb-populate-table-postgres -test-exchangedb-populate-link-data-postgres -test-exchangedb-populate-ready-deposit-postgres diff --git a/src/exchangedb/0002-deposits.sql b/src/exchangedb/0002-deposits.sql index 92210afa..d8afdac8 100644 --- a/src/exchangedb/0002-deposits.sql +++ b/src/exchangedb/0002-deposits.sql @@ -1,6 +1,6 @@  --  -- This file is part of TALER --- Copyright (C) 2014--2022 Taler Systems SA +-- Copyright (C) 2014--2023 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 @@ -116,6 +116,22 @@ BEGIN      ',ADD CONSTRAINT ' || table_name || '_coin_pub_merchant_pub_h_contract_terms_key'      ' UNIQUE (coin_pub, merchant_pub, h_contract_terms)'    ); +  EXECUTE FORMAT ( +    'CREATE INDEX ' || table_name || '_by_ready ' +    'ON ' || table_name || ' ' +    '(wire_deadline ASC' +    ',shard ASC' +    ',coin_pub' +    ') WHERE NOT (done OR policy_blocked);' +  ); +  EXECUTE FORMAT ( +    'CREATE INDEX ' || table_name || '_for_matching ' +    'ON ' || table_name || ' ' +    '(refund_deadline ASC' +    ',merchant_pub' +    ',coin_pub' +    ') WHERE NOT (done OR policy_blocked);' +  );  END  $$; @@ -399,29 +415,5 @@ INSERT INTO exchange_tables      ,'exchange-0002'      ,'foreign'      ,TRUE -    ,FALSE), -    ('deposits_by_ready' -    ,'exchange-0002' -    ,'create' -    ,TRUE -    ,TRUE), -    ('deposits_by_ready' -    ,'exchange-0002' -    ,'constrain' -    ,TRUE -    ,TRUE), -    ('deposits_for_matching' -    ,'exchange-0002' -    ,'create' -    ,TRUE -    ,TRUE), -    ('deposits_for_matching' -    ,'exchange-0002' -    ,'constrain' -    ,TRUE -    ,TRUE), -    ('deposits' -    ,'exchange-0002' -    ,'master' -    ,TRUE -    ,FALSE); +    ,FALSE) +    ; diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am index e8ef104e..49bc649b 100644 --- a/src/exchangedb/Makefile.am +++ b/src/exchangedb/Makefile.am @@ -255,8 +255,6 @@ libtaler_plugin_exchangedb_postgres_la_SOURCES = \    pg_select_purse_deposits_above_serial_id.h pg_select_purse_deposits_above_serial_id.c \    pg_select_account_merges_above_serial_id.h pg_select_account_merges_above_serial_id.c \    pg_select_all_purse_decisions_above_serial_id.h pg_select_all_purse_decisions_above_serial_id.c \ -  pg_batch_reserves_in_insert.h pg_batch_reserves_in_insert.c \ -  pg_batch2_reserves_in_insert.h pg_batch2_reserves_in_insert.c \    pg_select_reserve_open_above_serial_id.c pg_select_reserve_open_above_serial_id.h  libtaler_plugin_exchangedb_postgres_la_LIBADD = \    $(LTLIBINTL) @@ -295,22 +293,14 @@ check_PROGRAMS = \  noinst_PROGRAMS = \    bench-db-postgres\ -  perf-exchangedb-reserves-in-insert-postgres\ -  test-exchangedb-by-j-postgres\ -  test-exchangedb-batch-reserves-in-insert-postgres\ -  test-exchangedb-populate-select-refunds-by-coin-postgres\ -  test-exchangedb-populate-link-data-postgres\ -  test-exchangedb-populate-ready-deposit-postgres +  perf_get_link_data-postgres\ +  perf_select_refunds_by_coin-postgres\ +  perf_reserves_in_insert-postgres \ +  perf_deposits_get_ready-postgres  AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;  TESTS = \ -  test-exchangedb-postgres\ -  test-exchangedb-by-j-postgres\ -  perf-exchangedb-reserves-in-insert-postgres\ -  test-exchangedb-batch-reserves-in-insert-postgres\ -  test-exchangedb-populate-select-refunds-by-coin-postgres\ -  test-exchangedb-populate-link-data-postgres\ -  test-exchangedb-populate-ready-deposit-postgres +  (check_PROGRAMS)  test_exchangedb_postgres_SOURCES = \    test_exchangedb.c  test_exchangedb_postgres_LDADD = \ @@ -323,32 +313,6 @@ test_exchangedb_postgres_LDADD = \    -lgnunetutil \    $(XLIB) -test_exchangedb_by_j_postgres_SOURCES = \ -  test_exchangedb_by_j.c -test_exchangedb_by_j_postgres_LDADD = \ -  libtalerexchangedb.la \ -  $(top_builddir)/src/json/libtalerjson.la \ -  $(top_builddir)/src/util/libtalerutil.la \ -  $(top_builddir)/src/pq/libtalerpq.la \ -  -ljansson \ -  -lgnunetjson \ -  -lgnunetutil \ -  -lm \ -  $(XLIB) - - -perf_exchangedb_reserves_in_insert_postgres_SOURCES = \ -  perf_exchangedb_reserves_in_insert.c -perf_exchangedb_reserves_in_insert_postgres_LDADD = \ -  libtalerexchangedb.la \ -  $(top_builddir)/src/json/libtalerjson.la \ -  $(top_builddir)/src/util/libtalerutil.la \ -  $(top_builddir)/src/pq/libtalerpq.la \ -  -ljansson \ -  -lgnunetjson \ -  -lgnunetutil \ -  $(XLIB) -  bench_db_postgres_SOURCES = \    bench_db.c  bench_db_postgres_LDADD = \ @@ -359,9 +323,9 @@ bench_db_postgres_LDADD = \    -lgnunetutil \    $(XLIB) -test_exchangedb_batch_reserves_in_insert_postgres_SOURCES = \ -  test_exchangedb_batch_reserves_in_insert.c -test_exchangedb_batch_reserves_in_insert_postgres_LDADD = \ +perf_reserves_in_insert_postgres_SOURCES = \ +  perf_reserves_in_insert.c +perf_reserves_in_insert_postgres_LDADD = \    libtalerexchangedb.la \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/util/libtalerutil.la \ @@ -369,11 +333,12 @@ test_exchangedb_batch_reserves_in_insert_postgres_LDADD = \    -ljansson \    -lgnunetjson \    -lgnunetutil \ +  -lm \    $(XLIB) -test_exchangedb_populate_select_refunds_by_coin_postgres_SOURCES = \ -  test_exchangedb_populate_select_refunds_by_coin.c -test_exchangedb_populate_select_refunds_by_coin_postgres_LDADD = \ +perf_select_refunds_by_coin_postgres_SOURCES = \ +  perf_select_refunds_by_coin.c +perf_select_refunds_by_coin_postgres_LDADD = \    libtalerexchangedb.la \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/util/libtalerutil.la \ @@ -384,9 +349,9 @@ test_exchangedb_populate_select_refunds_by_coin_postgres_LDADD = \    -lm \    $(XLIB) -test_exchangedb_populate_link_data_postgres_SOURCES = \ -  test_exchangedb_populate_link_data.c -test_exchangedb_populate_link_data_postgres_LDADD = \ +perf_get_link_data_postgres_SOURCES = \ +  perf_get_link_data.c +perf_get_link_data_postgres_LDADD = \    libtalerexchangedb.la \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/util/libtalerutil.la \ @@ -397,9 +362,9 @@ test_exchangedb_populate_link_data_postgres_LDADD = \    -lm \    $(XLIB) -test_exchangedb_populate_ready_deposit_postgres_SOURCES = \ -  test_exchangedb_populate_ready_deposit.c -test_exchangedb_populate_ready_deposit_postgres_LDADD = \ +perf_deposits_get_ready_postgres_SOURCES = \ +  perf_deposits_get_ready.c +perf_deposits_get_ready_postgres_LDADD = \    libtalerexchangedb.la \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/util/libtalerutil.la \ diff --git a/src/exchangedb/test_exchangedb_populate_ready_deposit.c b/src/exchangedb/perf_deposits_get_ready.c index 97273fc9..4ad08223 100644 --- a/src/exchangedb/test_exchangedb_populate_ready_deposit.c +++ b/src/exchangedb/perf_deposits_get_ready.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2022 Taler Systems SA +  Copyright (C) 2014-2023 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 @@ -14,8 +14,8 @@    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>  */  /** - * @file exchangedb/test_exchangedb_populate_ready_deposit.c - * @brief test cases for DB interaction functions + * @file exchangedb/perf_deposits_get_ready.c + * @brief benchmark for deposits_get_ready   * @author Joseph Xu   */  #include "platform.h" @@ -34,7 +34,7 @@ static int result;   */  #define FAILIF(cond)                            \    do {                                          \ -      if (! (cond)) {break;}                    \ +    if (! (cond)) {break;}                    \      GNUNET_break (0);                           \      goto drop;                                  \    } while (0) @@ -57,21 +57,27 @@ static int result;   */  #define CURRENCY "EUR"  #define RSA_KEY_SIZE 1024 -#define NUM_ROWS 1000000 -#define ROUNDS 10000 +#define NUM_ROWS 1000 +#define ROUNDS 100  #define MELT_NEW_COINS 5  #define MELT_NOREVEAL_INDEX 1 +  /**   * Database plugin under test.   */  static struct TALER_EXCHANGEDB_Plugin *plugin; +  static struct TALER_DenomFeeSet fees; +  static struct TALER_MerchantWireHashP h_wire_wt; +  /**   * Denomination keys used for fresh coins in melt test.   */  static struct DenomKeyPair **new_dkp; +  static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; +  struct DenomKeyPair  {    struct TALER_DenominationPrivateKey priv; @@ -173,8 +179,6 @@ create_denom_key_pair (unsigned int size,  } - -  /**   * Main function that will be run by the scheduler.   * @@ -191,19 +195,19 @@ run (void *cls)    struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;    struct TALER_DenominationPublicKey *new_denom_pubs = NULL;    struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO; -  unsigned long long sqrs=0; -  struct TALER_EXCHANGEDB_Deposit *depos=NULL; -  struct TALER_EXCHANGEDB_Refund *ref=NULL; +  unsigned long long sqrs = 0; +  struct TALER_EXCHANGEDB_Deposit *depos = NULL; +  struct TALER_EXCHANGEDB_Refund *ref = NULL;    unsigned int *perm;    unsigned long long duration_sq;    struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;    struct TALER_ExchangeWithdrawValues alg_values = {      .cipher = TALER_DENOMINATION_RSA -    }; +  }; -  ref = GNUNET_new_array (ROUNDS +1, +  ref = GNUNET_new_array (ROUNDS + 1,                            struct TALER_EXCHANGEDB_Refund); -  depos = GNUNET_new_array (ROUNDS +1, +  depos = GNUNET_new_array (ROUNDS + 1,                              struct TALER_EXCHANGEDB_Deposit);    if (NULL == @@ -245,194 +249,190 @@ run (void *cls)    GNUNET_assert (GNUNET_OK ==                   TALER_string_to_amount (CURRENCY ":0.000010",                                           &fees.refund)); -  //DENOMINATION    {      ZR_BLK (&cbc); -    //PAIR KEY LIST      new_dkp = GNUNET_new_array (MELT_NEW_COINS, -                              struct DenomKeyPair *); -    //PUBLIC KEY LIST +                                struct DenomKeyPair *);      new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,                                         struct TALER_DenominationPublicKey); -    //REFRESH REVEAL COIN LIST      revealed_coins        = GNUNET_new_array (MELT_NEW_COINS,                            struct TALER_EXCHANGEDB_RefreshRevealedCoin);      for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) -      { -        struct GNUNET_TIME_Timestamp now; -        struct TALER_BlindedRsaPlanchet *rp; -        struct TALER_BlindedPlanchet *bp; - -        now = GNUNET_TIME_timestamp_get (); -        //5 KEY PAIR -        new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, -                                              now, -                                              &value, -                                              &fees); -        GNUNET_assert (NULL != new_dkp[cnt]); -        new_denom_pubs[cnt] = new_dkp[cnt]->pub; -        ccoin = &revealed_coins[cnt]; -        bp = &ccoin->blinded_planchet; -        bp->cipher = TALER_DENOMINATION_RSA; -        rp = &bp->details.rsa_blinded_planchet; -        rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( -                                                                      GNUNET_CRYPTO_QUALITY_WEAK, -                                                                      (RSA_KEY_SIZE / 8) - 1); -        rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); -        GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, -                                    rp->blinded_msg, -                                    rp->blinded_msg_size); -        TALER_denom_pub_hash (&new_dkp[cnt]->pub, -                              &ccoin->h_denom_pub); -        ccoin->exchange_vals = alg_values; -        TALER_coin_ev_hash (bp, -                            &ccoin->h_denom_pub, -                            &ccoin->coin_envelope_hash); -        GNUNET_assert (GNUNET_OK == +    { +      struct GNUNET_TIME_Timestamp now; +      struct TALER_BlindedRsaPlanchet *rp; +      struct TALER_BlindedPlanchet *bp; + +      now = GNUNET_TIME_timestamp_get (); +      new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, +                                            now, +                                            &value, +                                            &fees); +      GNUNET_assert (NULL != new_dkp[cnt]); +      new_denom_pubs[cnt] = new_dkp[cnt]->pub; +      ccoin = &revealed_coins[cnt]; +      bp = &ccoin->blinded_planchet; +      bp->cipher = TALER_DENOMINATION_RSA; +      rp = &bp->details.rsa_blinded_planchet; +      rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( +        GNUNET_CRYPTO_QUALITY_WEAK, +        (RSA_KEY_SIZE / 8) - 1); +      rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); +      GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, +                                  rp->blinded_msg, +                                  rp->blinded_msg_size); +      TALER_denom_pub_hash (&new_dkp[cnt]->pub, +                            &ccoin->h_denom_pub); +      ccoin->exchange_vals = alg_values; +      TALER_coin_ev_hash (bp, +                          &ccoin->h_denom_pub, +                          &ccoin->coin_envelope_hash); +      GNUNET_assert (GNUNET_OK ==                       TALER_denom_sign_blinded (&ccoin->coin_sig,                                                 &new_dkp[cnt]->priv,                                                 true,                                                 bp)); -        GNUNET_assert (GNUNET_OK == -                       TALER_coin_ev_hash (bp, -                                           &cbc.denom_pub_hash, -                                           &cbc.h_coin_envelope)); -        GNUNET_assert ( -                       GNUNET_OK == -                       TALER_denom_sign_blinded ( -                                                 &cbc.sig, -                                                 &new_dkp[cnt]->priv, -                                                 false, -                                                 bp)); -      } +      GNUNET_assert (GNUNET_OK == +                     TALER_coin_ev_hash (bp, +                                         &cbc.denom_pub_hash, +                                         &cbc.h_coin_envelope)); +      GNUNET_assert ( +        GNUNET_OK == +        TALER_denom_sign_blinded ( +          &cbc.sig, +          &new_dkp[cnt]->priv, +          false, +          bp)); +    }    }    perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE,                                         NUM_ROWS); -  //BEGIN    FAILIF (GNUNET_OK !=            plugin->start (plugin->cls,                           "Transaction"));    for (unsigned int j = 0; j < NUM_ROWS; j++) +  { +    /*** NEED TO INSERT REFRESH COMMITMENTS + ENSURECOIN ***/ +    union TALER_DenominationBlindingKeyP bks; +    struct GNUNET_TIME_Timestamp deadline; +    struct TALER_CoinSpendPublicKeyP coin_pub; +    struct TALER_ReservePublicKeyP reserve_pub; +    struct TALER_CoinPubHashP c_hash; +    unsigned int k = (unsigned int) rand () % 5; +    unsigned int i = perm[j]; +    if (i >= ROUNDS) +      i = ROUNDS;   /* throw-away slot, do not keep around */ +    depos[i].deposit_fee = fees.deposit; +    RND_BLK (&coin_pub); +    RND_BLK (&c_hash); +    RND_BLK (&reserve_pub); +    RND_BLK (&cbc.reserve_sig); +    TALER_denom_pub_hash (&new_dkp[k]->pub, +                          &cbc.denom_pub_hash); +    deadline = GNUNET_TIME_timestamp_get (); +    RND_BLK (&depos[i].coin.coin_pub); +    TALER_denom_pub_hash (&new_dkp[k]->pub, +                          &depos[i].coin.denom_pub_hash); +    GNUNET_assert (GNUNET_OK == +                   TALER_denom_sig_unblind (&depos[i].coin.denom_sig, +                                            &ccoin->coin_sig, +                                            &bks, +                                            &c_hash, +                                            &alg_values, +                                            &new_dkp[k]->pub)); +    RND_BLK (&depos[i].merchant_pub); +    RND_BLK (&depos[i].csig); +    RND_BLK (&depos[i].h_contract_terms); +    RND_BLK (&depos[i].wire_salt); +    depos[i].amount_with_fee = value; +    depos[i].refund_deadline = deadline; +    depos[i].wire_deadline = deadline; +    depos[i].receiver_wire_account = +      "payto://iban/DE67830654080004822650?receiver-name=Test"; +    TALER_merchant_wire_signature_hash ( +      "payto://iban/DE67830654080004822650?receiver-name=Test", +      &depos[i].wire_salt, +      &h_wire_wt); +    cbc.reserve_pub = reserve_pub; +    cbc.amount_with_fee = value; +    GNUNET_assert (GNUNET_OK == +                   TALER_amount_set_zero (CURRENCY, +                                          &cbc.withdraw_fee));      { -      /*** NEED TO INSERT REFRESH COMMITMENTS + ENSURECOIN ***/ -      union TALER_DenominationBlindingKeyP bks; -      struct GNUNET_TIME_Timestamp deadline; -      struct TALER_CoinSpendPublicKeyP coin_pub; -      struct TALER_ReservePublicKeyP reserve_pub; -      struct TALER_CoinPubHashP c_hash; -      unsigned int k = (unsigned int)rand()%5; -      unsigned int i = perm[j]; -      if (i >= ROUNDS) -        i = ROUNDS; /* throw-away slot, do not keep around */ -      depos[i].deposit_fee = fees.deposit; -      RND_BLK (&coin_pub); -      RND_BLK (&c_hash); -      RND_BLK (&reserve_pub); -      RND_BLK (&cbc.reserve_sig); -      TALER_denom_pub_hash (&new_dkp[k]->pub, -                            &cbc.denom_pub_hash); -      deadline = GNUNET_TIME_timestamp_get (); -      RND_BLK (&depos[i].coin.coin_pub); -      TALER_denom_pub_hash (&new_dkp[k]->pub, -                            &depos[i].coin.denom_pub_hash); -      GNUNET_assert (GNUNET_OK == -                     TALER_denom_sig_unblind (&depos[i].coin.denom_sig, -                                              &ccoin->coin_sig, -                                              &bks, -                                              &c_hash, -                                              &alg_values, -                                              &new_dkp[k]->pub)); -      RND_BLK (&depos[i].merchant_pub); -      RND_BLK (&depos[i].csig); -      RND_BLK (&depos[i].h_contract_terms); -      RND_BLK (&depos[i].wire_salt); -      depos[i].amount_with_fee = value; -      depos[i].refund_deadline = deadline; -      depos[i].wire_deadline = deadline; -      depos[i].receiver_wire_account = -        "payto://iban/DE67830654080004822650?receiver-name=Test"; -      TALER_merchant_wire_signature_hash ( -                                          "payto://iban/DE67830654080004822650?receiver-name=Test", -                                          &depos[i].wire_salt, -                                          &h_wire_wt); -      cbc.reserve_pub = reserve_pub; -      cbc.amount_with_fee = value; -      GNUNET_assert (GNUNET_OK == -                     TALER_amount_set_zero (CURRENCY, -                                            &cbc.withdraw_fee)); -      { -        /* INSERT WIRE TARGETS */ -        bool found; -        bool nonce_ok; -        bool balance_ok; -        uint64_t ruuid; -        struct GNUNET_TIME_Timestamp now; -        now = GNUNET_TIME_timestamp_get (); -        FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != -                plugin->do_withdraw (plugin->cls, -                                     NULL, -                                     &cbc, -                                     now, -                                     &found, -                                     &balance_ok, -                                     &nonce_ok, -                                     &ruuid)); -      } -      { -        /* ENSURE_COIN_KNOWN */ -        uint64_t known_coin_id; -        struct TALER_DenominationHashP dph; -        struct TALER_AgeCommitmentHash agh; -        FAILIF (TALER_EXCHANGEDB_CKS_ADDED != -                plugin->ensure_coin_known (plugin->cls, -                                           &depos[i].coin, -                                           &known_coin_id, -                                           &dph, -                                           &agh)); -        refresh.coin = depos[i].coin; -        RND_BLK (&refresh.coin_sig); -        RND_BLK (&refresh.rc); -        refresh.amount_with_fee = value; -        refresh.noreveal_index = MELT_NOREVEAL_INDEX; -      } -        /*STORE INTO DEPOSIT*/ -      { -        struct GNUNET_TIME_Timestamp now; -        now = GNUNET_TIME_timestamp_get (); -        FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != -                plugin->insert_deposit (plugin->cls, -                                        now, -                                        &depos[i])); -      } -      if (ROUNDS == i) -        TALER_denom_sig_free (&depos[i].coin.denom_sig); +      bool found; +      bool nonce_ok; +      bool balance_ok; +      uint64_t ruuid; +      struct GNUNET_TIME_Timestamp now; + +      now = GNUNET_TIME_timestamp_get (); +      FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != +              plugin->do_withdraw (plugin->cls, +                                   NULL, +                                   &cbc, +                                   now, +                                   &found, +                                   &balance_ok, +                                   &nonce_ok, +                                   &ruuid));      } -  /* End of benchmark setup */ -  GNUNET_free(perm); -  // commit +    { +      /* ENSURE_COIN_KNOWN */ +      uint64_t known_coin_id; +      struct TALER_DenominationHashP dph; +      struct TALER_AgeCommitmentHash agh; +      FAILIF (TALER_EXCHANGEDB_CKS_ADDED != +              plugin->ensure_coin_known (plugin->cls, +                                         &depos[i].coin, +                                         &known_coin_id, +                                         &dph, +                                         &agh)); +      refresh.coin = depos[i].coin; +      RND_BLK (&refresh.coin_sig); +      RND_BLK (&refresh.rc); +      refresh.amount_with_fee = value; +      refresh.noreveal_index = MELT_NOREVEAL_INDEX; +    } +    { +      struct GNUNET_TIME_Timestamp now; + +      now = GNUNET_TIME_timestamp_get (); +      FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != +              plugin->insert_deposit (plugin->cls, +                                      now, +                                      &depos[i])); +    } +    if (ROUNDS == i) +      TALER_denom_sig_free (&depos[i].coin.denom_sig); +  }    FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=            plugin->commit (plugin->cls)); +  GNUNET_free (perm); +  /* End of benchmark setup */ +    /**** CALL GET READY DEPOSIT ****/ -  for (unsigned int r=0; r< ROUNDS; r++) +  for (unsigned int r = 0; r< ROUNDS; r++)    {      struct GNUNET_TIME_Absolute time;      struct GNUNET_TIME_Relative duration;      struct TALER_MerchantPublicKeyP merchant_pub;      char *payto_uri; -    time = GNUNET_TIME_absolute_get(); -    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != -            plugin->get_ready_deposit (plugin->cls, -                                       0, -                                       INT32_MAX, -                                       &merchant_pub, -                                       &payto_uri)); +    enum GNUNET_DB_QueryStatus qs; +    time = GNUNET_TIME_absolute_get (); +    qs = plugin->get_ready_deposit (plugin->cls, +                                    0, +                                    INT32_MAX, +                                    &merchant_pub, +                                    &payto_uri); +    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);      duration = GNUNET_TIME_absolute_get_duration (time);      times = GNUNET_TIME_relative_add (times,                                        duration);      duration_sq = duration.rel_value_us * duration.rel_value_us; -    GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us); +    GNUNET_assert (duration_sq / duration.rel_value_us == +                   duration.rel_value_us);      GNUNET_assert (sqrs + duration_sq >= sqrs);      sqrs += duration_sq;    } @@ -447,15 +447,14 @@ run (void *cls)                                         ROUNDS);      avg_dbl = avg.rel_value_us;      variance = sqrs - (avg_dbl * avg_dbl * ROUNDS); -    fprintf(stdout, -            "%8llu ± %6.0f\n", -            (unsigned long long) avg.rel_value_us, -            sqrt (variance / (ROUNDS-1))); +    fprintf (stdout, +             "%8llu ± %6.0f\n", +             (unsigned long long) avg.rel_value_us, +             sqrt (variance / (ROUNDS - 1)));    }    result = 0;  drop: -  GNUNET_break (GNUNET_OK == -  plugin->drop_tables (plugin->cls)); +  // GNUNET_break (GNUNET_OK == plugin->drop_tables (plugin->cls));  cleanup:    if (NULL != revealed_coins)    { @@ -473,12 +472,12 @@ cleanup:         cnt++)      destroy_denom_key_pair (new_dkp[cnt]);    GNUNET_free (new_dkp); -  for (unsigned int i=0; i< ROUNDS ; i++) -    { -      TALER_denom_sig_free (&depos[i].coin.denom_sig); -    } -  GNUNET_free(depos); -  GNUNET_free(ref); +  for (unsigned int i = 0; i< ROUNDS; i++) +  { +    TALER_denom_sig_free (&depos[i].coin.denom_sig); +  } +  GNUNET_free (depos); +  GNUNET_free (ref);    TALER_EXCHANGEDB_plugin_unload (plugin);    plugin = NULL;  } @@ -490,7 +489,6 @@ main (int argc,  {    const char *plugin_name;    char *config_filename; -  char *testname;    struct GNUNET_CONFIGURATION_Handle *cfg;    (void) argc; @@ -504,15 +502,17 @@ main (int argc,                      "WARNING",                      NULL);    plugin_name++; -  (void) GNUNET_asprintf (&testname, -                          "test-exchange-db-%s", -                          plugin_name); -  (void) GNUNET_asprintf (&config_filename, -                          "%s.conf", -                          testname); -  fprintf (stdout, -           "Using config: %s\n", -           config_filename); +  { +    char *testname; + +    GNUNET_asprintf (&testname, +                     "test-exchange-db-%s", +                     plugin_name); +    GNUNET_asprintf (&config_filename, +                     "%s.conf", +                     testname); +    GNUNET_free (testname); +  }    cfg = GNUNET_CONFIGURATION_create ();    if (GNUNET_OK !=        GNUNET_CONFIGURATION_parse (cfg, @@ -520,16 +520,14 @@ main (int argc,    {      GNUNET_break (0);      GNUNET_free (config_filename); -    GNUNET_free (testname);      return 2;    }    GNUNET_SCHEDULER_run (&run,                          cfg);    GNUNET_CONFIGURATION_destroy (cfg);    GNUNET_free (config_filename); -  GNUNET_free (testname);    return result;  } -/* end of test_exchangedb_by_j.c */ +/* end of perf_deposits_get_ready.c */ diff --git a/src/exchangedb/test_exchangedb_populate_link_data.c b/src/exchangedb/perf_get_link_data.c index 84e5ab88..eb1f5f6e 100644 --- a/src/exchangedb/test_exchangedb_populate_link_data.c +++ b/src/exchangedb/perf_get_link_data.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2022 Taler Systems SA +  Copyright (C) 2014-2023 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 @@ -14,8 +14,8 @@    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>  */  /** - * @file exchangedb/test_exchangedb_populate_link_data.c - * @brief test cases for DB interaction functions + * @file exchangedb/perf_get_link_data.c + * @brief benchmark for get_link_data   * @author Joseph Xu   */  #include "platform.h" @@ -29,7 +29,7 @@   */  #define FAILIF(cond)                            \    do {                                          \ -      if (! (cond)) {break;}                    \ +    if (! (cond)) {break;}                    \      GNUNET_break (0);                           \      goto drop;                                  \    } while (0) @@ -166,6 +166,8 @@ create_denom_key_pair (unsigned int size,    }    return dkp;  } + +  /**   * Function called with the session hashes and transfer secret   * information for a given coin. @@ -199,22 +201,22 @@ run (void *cls)    struct GNUNET_CONFIGURATION_Handle *cfg = cls;    const uint32_t num_partitions = 10;    struct DenomKeyPair *dkp = NULL; -  struct TALER_EXCHANGEDB_Deposit *depos=NULL; +  struct TALER_EXCHANGEDB_Deposit *depos = NULL;    struct TALER_Amount value;    struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO; -  unsigned long long sqrs=0; -  struct TALER_EXCHANGEDB_Refund *ref=NULL; +  unsigned long long sqrs = 0; +  struct TALER_EXCHANGEDB_Refund *ref = NULL;    unsigned int *perm;    unsigned long long duration_sq;    struct TALER_ExchangeWithdrawValues alg_values = {      .cipher = TALER_DENOMINATION_RSA -    }; +  }; -  ref = GNUNET_new_array (ROUNDS +1, +  ref = GNUNET_new_array (ROUNDS + 1,                            struct TALER_EXCHANGEDB_Refund); -  depos = GNUNET_new_array (ROUNDS +1, +  depos = GNUNET_new_array (ROUNDS + 1,                              struct TALER_EXCHANGEDB_Deposit); -  refresh = GNUNET_new_array (ROUNDS +1, +  refresh = GNUNET_new_array (ROUNDS + 1,                                struct TALER_EXCHANGEDB_Refresh);    if (NULL == @@ -256,16 +258,14 @@ run (void *cls)    GNUNET_assert (GNUNET_OK ==                   TALER_string_to_amount (CURRENCY ":0.000010",                                           &fees.refund)); -  //DENOMINATION    { -    //PAIR KEY LIST      new_dkp = GNUNET_new_array (MELT_NEW_COINS,                                  struct DenomKeyPair *);      for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)      {        struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); -       +        new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE,                                              now,                                              &value, @@ -275,7 +275,6 @@ run (void *cls)    }    perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE,                                         NUM_ROWS); -  //BEGIN    FAILIF (GNUNET_OK !=            plugin->start (plugin->cls,                           "Transaction")); @@ -290,89 +289,96 @@ run (void *cls)        i = ROUNDS; /* throw-away slot, do not keep around */      RND_BLK (&depos[i].coin.coin_pub);      ZR_BLK (&cbc); -    TALER_denom_pub_hash (&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub, +    TALER_denom_pub_hash (&new_dkp[(unsigned int) rand () +                                   % MELT_NEW_COINS]->pub,                            &depos[i].coin.denom_pub_hash); -          { -      struct TALER_EXCHANGEDB_RefreshRevealedCoin revealed_coins[MELT_NEW_COINS]; -       -      for (unsigned int p=0;p<MELT_NEW_COINS;p++) -        { -          struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coin = &revealed_coins[p]; -          struct TALER_BlindedPlanchet *bp = &revealed_coin->blinded_planchet; -          struct TALER_BlindedRsaPlanchet *rp = &bp->details.rsa_blinded_planchet; -           -          /* h_coin_ev must be unique, but we only have MELT_NEW_COINS created -             above for NUM_ROWS iterations; instead of making "all new" coins, -             we simply randomize the hash here as nobody is checking for consistency -             anyway ;-) */ -          bp->cipher = TALER_DENOMINATION_RSA; -          rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( -                                                                        GNUNET_CRYPTO_QUALITY_WEAK, -                                                                        (RSA_KEY_SIZE / 8) - 1); -          rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); -          GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, -                                      rp->blinded_msg, -                                      rp->blinded_msg_size); -          TALER_denom_pub_hash (&new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub, -                                &revealed_coin->h_denom_pub); -          revealed_coin->exchange_vals = alg_values; -          TALER_coin_ev_hash (bp, -                              &revealed_coin->h_denom_pub, -                              &revealed_coin->coin_envelope_hash);  -          GNUNET_assert (GNUNET_OK == -                         TALER_denom_sign_blinded (&revealed_coin->coin_sig, -                                                   &new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->priv, -                                                   true, -                                                   bp)); -          GNUNET_assert ( -                         GNUNET_OK == -                         TALER_denom_sign_blinded ( -                                                   &cbc.sig, -                                                   &new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->priv, -                                                   false, -                                                   bp)); -        } -    GNUNET_assert (GNUNET_OK == -                   TALER_denom_sig_unblind (&depos[i].coin.denom_sig, -                                            &cbc.sig, -                                            &bks, -                                            &c_hash, -                                            &alg_values, -                                            &new_dkp[(unsigned int)rand()%MELT_NEW_COINS]->pub)); -    { -      /* ENSURE_COIN_KNOWN */ -      struct TALER_DenominationHashP dph; -      struct TALER_AgeCommitmentHash agh; -      bool zombie_required = false; -      bool balance_ok; - -      FAILIF (TALER_EXCHANGEDB_CKS_ADDED != -              plugin->ensure_coin_known (plugin->cls, -                                         &depos[i].coin, -                                         &known_coin_id, -                                         &dph, -                                         &agh)); -      /**** INSERT REFRESH COMMITMENTS ****/ -      refresh[i].coin = depos[i].coin; -      RND_BLK (&refresh[i].coin_sig); -      RND_BLK (&refresh[i].rc); -      refresh[i].amount_with_fee = value; -      refresh[i].noreveal_index = MELT_NOREVEAL_INDEX; -      FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != -              plugin->do_melt (plugin->cls, -                               NULL, -                               &refresh[i], -                               known_coin_id, -                               &zombie_required, -                               &balance_ok)); -    } +      struct TALER_EXCHANGEDB_RefreshRevealedCoin +        revealed_coins[MELT_NEW_COINS]; + +      for (unsigned int p = 0; p<MELT_NEW_COINS; p++) +      { +        struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coin = +          &revealed_coins[p]; +        struct TALER_BlindedPlanchet *bp = &revealed_coin->blinded_planchet; +        struct TALER_BlindedRsaPlanchet *rp = &bp->details.rsa_blinded_planchet; + +        /* h_coin_ev must be unique, but we only have MELT_NEW_COINS created +           above for NUM_ROWS iterations; instead of making "all new" coins, +           we simply randomize the hash here as nobody is checking for consistency +           anyway ;-) */ +        bp->cipher = TALER_DENOMINATION_RSA; +        rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( +          GNUNET_CRYPTO_QUALITY_WEAK, +          (RSA_KEY_SIZE / 8) - 1); +        rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); +        GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, +                                    rp->blinded_msg, +                                    rp->blinded_msg_size); +        TALER_denom_pub_hash (&new_dkp[(unsigned int) rand () +                                       % MELT_NEW_COINS]->pub, +                              &revealed_coin->h_denom_pub); +        revealed_coin->exchange_vals = alg_values; +        TALER_coin_ev_hash (bp, +                            &revealed_coin->h_denom_pub, +                            &revealed_coin->coin_envelope_hash); +        GNUNET_assert (GNUNET_OK == +                       TALER_denom_sign_blinded (&revealed_coin->coin_sig, +                                                 &new_dkp[(unsigned +                                                           int) rand () +                                                          % MELT_NEW_COINS]-> +                                                 priv, +                                                 true, +                                                 bp)); +        GNUNET_assert ( +          GNUNET_OK == +          TALER_denom_sign_blinded ( +            &cbc.sig, +            &new_dkp[(unsigned int) rand () % MELT_NEW_COINS]->priv, +            false, +            bp)); +      } +      GNUNET_assert (GNUNET_OK == +                     TALER_denom_sig_unblind (&depos[i].coin.denom_sig, +                                              &cbc.sig, +                                              &bks, +                                              &c_hash, +                                              &alg_values, +                                              &new_dkp[(unsigned int) rand () +                                                       % MELT_NEW_COINS]->pub)); +      { +        /* ENSURE_COIN_KNOWN */ +        struct TALER_DenominationHashP dph; +        struct TALER_AgeCommitmentHash agh; +        bool zombie_required = false; +        bool balance_ok; + +        FAILIF (TALER_EXCHANGEDB_CKS_ADDED != +                plugin->ensure_coin_known (plugin->cls, +                                           &depos[i].coin, +                                           &known_coin_id, +                                           &dph, +                                           &agh)); +        /**** INSERT REFRESH COMMITMENTS ****/ +        refresh[i].coin = depos[i].coin; +        RND_BLK (&refresh[i].coin_sig); +        RND_BLK (&refresh[i].rc); +        refresh[i].amount_with_fee = value; +        refresh[i].noreveal_index = MELT_NOREVEAL_INDEX; +        FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != +                plugin->do_melt (plugin->cls, +                                 NULL, +                                 &refresh[i], +                                 known_coin_id, +                                 &zombie_required, +                                 &balance_ok)); +      }        /****GET melt_serial_id generated by default****/        {          struct TALER_EXCHANGEDB_Melt ret_refresh_session; -         +          FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=                  plugin->get_melt (plugin->cls,                                    &refresh[i].rc, @@ -382,7 +388,7 @@ run (void *cls)        /**** INSERT REFRESH_REVEAL + TRANSFER_KEYS *****/        {          static unsigned int cnt; -         +          RND_BLK (&tprivs);          RND_BLK (&tpub);          FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != @@ -398,14 +404,14 @@ run (void *cls)        }        for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)        { -          TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig); -          TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet); +        TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig); +        TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet);        } -     +        /*      {          struct TALER_CoinSpendPublicKeyP ocp;          uint64_t rrc_serial; -         +          FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=                  plugin->get_old_coin_by_h_blind (plugin->cls,                                                   &revealed_coins->coin_envelope_hash, @@ -417,17 +423,15 @@ run (void *cls)        TALER_denom_sig_free (&depos[i].coin.denom_sig);    }    /* End of benchmark setup */ -  GNUNET_free(perm); -  // commit +  GNUNET_free (perm);    FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=            plugin->commit (plugin->cls)); -  /**** CALL GET LINK DATA ****/ -  for (unsigned int r=0; r< ROUNDS; r++) +  for (unsigned int r = 0; r< ROUNDS; r++)    {      struct GNUNET_TIME_Absolute time;      struct GNUNET_TIME_Relative duration;      enum GNUNET_DB_QueryStatus qs; -    time = GNUNET_TIME_absolute_get(); +    time = GNUNET_TIME_absolute_get ();      qs = plugin->get_link_data (plugin->cls,                                  &refresh[r].coin.coin_pub, @@ -439,7 +443,8 @@ run (void *cls)      times = GNUNET_TIME_relative_add (times,                                        duration);      duration_sq = duration.rel_value_us * duration.rel_value_us; -    GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us); +    GNUNET_assert (duration_sq / duration.rel_value_us == +                   duration.rel_value_us);      GNUNET_assert (sqrs + duration_sq >= sqrs);      sqrs += duration_sq;    } @@ -454,10 +459,10 @@ run (void *cls)                                         ROUNDS);      avg_dbl = avg.rel_value_us;      variance = sqrs - (avg_dbl * avg_dbl * ROUNDS); -    fprintf(stdout, -            "%8llu ± %6.0f\n", -            (unsigned long long) avg.rel_value_us, -            sqrt (variance / (ROUNDS-1))); +    fprintf (stdout, +             "%8llu ± %6.0f\n", +             (unsigned long long) avg.rel_value_us, +             sqrt (variance / (ROUNDS - 1)));    }    result = 0;  drop: @@ -470,13 +475,13 @@ cleanup:         cnt++)      destroy_denom_key_pair (new_dkp[cnt]);    GNUNET_free (new_dkp); -  for (unsigned int i=0; i< ROUNDS; i++) -    { -      TALER_denom_sig_free (&depos[i].coin.denom_sig); -    } -  GNUNET_free(depos); -  GNUNET_free(ref); -  GNUNET_free(refresh); +  for (unsigned int i = 0; i< ROUNDS; i++) +  { +    TALER_denom_sig_free (&depos[i].coin.denom_sig); +  } +  GNUNET_free (depos); +  GNUNET_free (ref); +  GNUNET_free (refresh);    dkp = NULL;    TALER_EXCHANGEDB_plugin_unload (plugin);    plugin = NULL; @@ -509,9 +514,6 @@ main (int argc,    (void) GNUNET_asprintf (&config_filename,                            "%s.conf",                            testname); -  fprintf (stdout, -           "Using config: %s\n", -           config_filename);    cfg = GNUNET_CONFIGURATION_create ();    if (GNUNET_OK !=        GNUNET_CONFIGURATION_parse (cfg, diff --git a/src/exchangedb/perf_exchangedb_reserves_in_insert.c b/src/exchangedb/perf_reserves_in_insert.c index fc2a0008..9f3ed460 100644 --- a/src/exchangedb/perf_exchangedb_reserves_in_insert.c +++ b/src/exchangedb/perf_reserves_in_insert.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2022 Taler Systems SA +  Copyright (C) 2014-2023 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 @@ -14,8 +14,8 @@    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>  */  /** - * @file exchangedb/test_exchangedb_by_j.c - * @brief test cases for DB interaction functions + * @file exchangedb/perf_reserves_in_insert.c + * @brief benchmark for 'reserves_in_insert'   * @author Joseph Xu   */  #include "platform.h" @@ -23,6 +23,7 @@  #include "taler_json_lib.h"  #include "taler_exchangedb_plugin.h" +  /**   * Global result from the testcase.   */ @@ -33,7 +34,7 @@ static int result;   */  #define FAILIF(cond)                            \    do {                                          \ -    if (! (cond)) { break;}                     \ +    if (! (cond)) {break;}                    \      GNUNET_break (0);                           \      goto drop;                                  \    } while (0) @@ -51,6 +52,10 @@ static int result;  #define ZR_BLK(ptr) \    memset (ptr, 0, sizeof (*ptr)) +/** + * How many rounds do we average over? + */ +#define ROUNDS 5  /**   * Currency we use.  Must match test-exchange-db-*.conf. @@ -73,6 +78,10 @@ run (void *cls)  {    struct GNUNET_CONFIGURATION_Handle *cfg = cls;    const uint32_t num_partitions = 10; +  static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 32 }; +  const unsigned int lcm = 3 * 32; +  struct GNUNET_TIME_Relative times[sizeof (batches) / sizeof(*batches)]; +  unsigned long long sqrs[sizeof (batches) / sizeof(*batches)];    if (NULL ==        (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) @@ -91,46 +100,78 @@ run (void *cls)      result = 77;      goto cleanup;    } -  for (unsigned int i = 0; i< 8; i++) + +  memset (times, 0, sizeof (times)); +  memset (sqrs, 0, sizeof (sqrs)); +  for (unsigned int r = 0; r < ROUNDS; r++)    { -    static unsigned int batches[] = {1, 1, 0, 2, 4, 16, 64, 256}; -    const char *sndr = "payto://x-taler-bank/localhost:8080/1"; -    struct TALER_Amount value; -    unsigned int batch_size = batches[i]; -    struct GNUNET_TIME_Absolute now; -    struct GNUNET_TIME_Timestamp ts; -    struct GNUNET_TIME_Relative duration; -    struct TALER_ReservePublicKeyP reserve_pub; - -    GNUNET_assert (GNUNET_OK == -                   TALER_string_to_amount (CURRENCY ":1.000010", -                                           &value)); -    now = GNUNET_TIME_absolute_get (); -    ts = GNUNET_TIME_timestamp_get (); -    for (unsigned int r = 0; r<10; r++) +    for (unsigned int i = 0; +         i< sizeof(batches) / sizeof(*batches); +         i++)      { -      plugin->start (plugin->cls, -                     "test_by_exchange_j"); -      for (unsigned int k = 0; k<batch_size; k++) +      unsigned int batch_size = batches[i]; +      struct TALER_Amount value; +      struct GNUNET_TIME_Absolute now; +      struct GNUNET_TIME_Timestamp ts; +      unsigned long long duration_sq; +      struct GNUNET_TIME_Relative duration; + +      GNUNET_assert (GNUNET_OK == +                     TALER_string_to_amount (CURRENCY ":1.000010", +                                             &value)); +      now = GNUNET_TIME_absolute_get (); +      ts = GNUNET_TIME_timestamp_get ();        { -        RND_BLK (&reserve_pub); -        FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != +        const char *sndr = "payto://x-taler-bank/localhost:8080/1"; +        struct TALER_ReservePublicKeyP reserve_pubs[lcm]; +        struct TALER_EXCHANGEDB_ReserveInInfo reserves[lcm]; +        enum GNUNET_DB_QueryStatus results[lcm]; + +        for (unsigned int k = 0; k<lcm; k++) +        { +          RND_BLK (&reserve_pubs[k]); +          reserves[k].reserve_pub = &reserve_pubs[k]; +          reserves[k].balance = &value; +          reserves[k].execution_time = ts; +          reserves[k].sender_account_details = sndr; +          reserves[k].exchange_account_name = "name"; +          reserves[k].wire_reference = k; +        } +        FAILIF (lcm !=                  plugin->reserves_in_insert (plugin->cls, -                                            &reserve_pub, -                                            &value, -                                            ts, -                                            sndr, -                                            "section", -                                            4)); +                                            reserves, +                                            lcm, +                                            batch_size, +                                            results));        } -      plugin->commit (plugin->cls); -    } -    duration = GNUNET_TIME_absolute_get_duration (now); +      duration = GNUNET_TIME_absolute_get_duration (now); +      times[i] = GNUNET_TIME_relative_add (times[i], +                                           duration); +      duration_sq = duration.rel_value_us * duration.rel_value_us; +      GNUNET_assert (duration_sq / duration.rel_value_us == +                     duration.rel_value_us); +      GNUNET_assert (sqrs[i] + duration_sq >= sqrs[i]); +      sqrs[i] += duration_sq; +    } /* for 'i' batch size */ +  } /* for 'r' ROUNDS */ + +  for (unsigned int i = 0; +       i< sizeof(batches) / sizeof(*batches); +       i++) +  { +    struct GNUNET_TIME_Relative avg; +    double avg_dbl; +    double variance; + +    avg = GNUNET_TIME_relative_divide (times[i], +                                       ROUNDS); +    avg_dbl = avg.rel_value_us; +    variance = sqrs[i] - (avg_dbl * avg_dbl * ROUNDS);      fprintf (stdout, -             "for a batchsize equal to %d it took %s\n", -             batch_size, -             GNUNET_STRINGS_relative_time_to_string (duration, -                                                     GNUNET_NO) ); +             "Batch[%2u]: %8llu ± %6.0f\n", +             batches[i], +             (unsigned long long) avg.rel_value_us, +             sqrt (variance / (ROUNDS - 1)));    }    result = 0;  drop: @@ -150,7 +191,6 @@ main (int argc,    char *config_filename;    char *testname;    struct GNUNET_CONFIGURATION_Handle *cfg; -    (void) argc;    result = -1;    if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) @@ -158,6 +198,7 @@ main (int argc,      GNUNET_break (0);      return -1;    } +    GNUNET_log_setup (argv[0],                      "WARNING",                      NULL); @@ -168,9 +209,6 @@ main (int argc,    (void) GNUNET_asprintf (&config_filename,                            "%s.conf",                            testname); -  fprintf (stdout, -           "Using config: %s\n", -           config_filename);    cfg = GNUNET_CONFIGURATION_create ();    if (GNUNET_OK !=        GNUNET_CONFIGURATION_parse (cfg, @@ -190,4 +228,4 @@ main (int argc,  } -/* end of test_exchangedb_by_j.c */ +/* end of perf_reserves_in_insert.c */ diff --git a/src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c b/src/exchangedb/perf_select_refunds_by_coin.c index c094b204..85c92f4b 100644 --- a/src/exchangedb/test_exchangedb_populate_select_refunds_by_coin.c +++ b/src/exchangedb/perf_select_refunds_by_coin.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2022 Taler Systems SA +  Copyright (C) 2014-2023 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 @@ -14,8 +14,8 @@    TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>  */  /** - * @file exchangedb/test_exchangedb_populate_table.c - * @brief test cases for DB interaction functions + * @file exchangedb/perf_select_refunds_by_coin.c + * @brief benchmark for select_refunds_by_coin   * @author Joseph Xu   */  #include "platform.h" @@ -34,7 +34,7 @@ static int result;   */  #define FAILIF(cond)                            \    do {                                          \ -      if (! (cond)) {break;}                    \ +    if (! (cond)) {break;}                    \      GNUNET_break (0);                           \      goto drop;                                  \    } while (0) @@ -56,24 +56,31 @@ static int result;   */  #define CURRENCY "EUR"  #define RSA_KEY_SIZE 1024 -#define ROUNDS 10000 -#define NUM_ROWS 1000000 +#define ROUNDS 100 +#define NUM_ROWS 1000  #define MELT_NEW_COINS 5  #define MELT_NOREVEAL_INDEX 1 +  /**   * Database plugin under test.   */  static struct TALER_EXCHANGEDB_Plugin *plugin; +  static struct TALER_DenomFeeSet fees; +  static struct TALER_MerchantWireHashP h_wire_wt; +  static struct DenomKeyPair **new_dkp; +  static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; +  struct DenomKeyPair  {    struct TALER_DenominationPrivateKey priv;    struct TALER_DenominationPublicKey pub;  }; +  /**   * Destroy a denomination key pair.  The key is not necessarily removed from the DB.   * @@ -166,6 +173,8 @@ create_denom_key_pair (unsigned int size,    }    return dkp;  } + +  /**   * Callback invoked with information about refunds applicable   * to a particular coin. @@ -179,6 +188,7 @@ check_refund_cb (void *cls,                   const struct TALER_Amount *amount_with_fee)  {    const struct TALER_EXCHANGEDB_Refund *refund = cls; +    if (0 != TALER_amount_cmp (amount_with_fee,                               &refund->details.refund_amount))    { @@ -201,7 +211,7 @@ run (void *cls)    struct GNUNET_CONFIGURATION_Handle *cfg = cls;    const uint32_t num_partitions = 10;    struct GNUNET_TIME_Timestamp ts; -  struct TALER_EXCHANGEDB_Deposit *depos=NULL; +  struct TALER_EXCHANGEDB_Deposit *depos = NULL;    struct GNUNET_TIME_Timestamp deadline;    struct TALER_Amount value;    union TALER_DenominationBlindingKeyP bks; @@ -209,20 +219,20 @@ run (void *cls)    struct TALER_EXCHANGEDB_CollectableBlindcoin cbc;    struct TALER_ExchangeWithdrawValues alg_values = {      .cipher = TALER_DENOMINATION_RSA -    }; +  };    struct GNUNET_TIME_Relative times = GNUNET_TIME_UNIT_ZERO;    unsigned long long sqrs = 0; -  struct TALER_EXCHANGEDB_Refund *ref=NULL; +  struct TALER_EXCHANGEDB_Refund *ref = NULL;    unsigned int *perm;    unsigned long long duration_sq;    struct TALER_CoinSpendPublicKeyP coin_pub;    struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;    struct TALER_DenominationPublicKey *new_denom_pubs = NULL; -  unsigned int count=0; +  unsigned int count = 0; -  ref = GNUNET_new_array (ROUNDS +1, +  ref = GNUNET_new_array (ROUNDS + 1,                            struct TALER_EXCHANGEDB_Refund); -  depos = GNUNET_new_array (ROUNDS +1, +  depos = GNUNET_new_array (ROUNDS + 1,                              struct TALER_EXCHANGEDB_Deposit);    ZR_BLK (&cbc); @@ -249,8 +259,6 @@ run (void *cls)      GNUNET_break (0);      goto cleanup;    } - -    GNUNET_assert (GNUNET_OK ==                   TALER_string_to_amount (CURRENCY ":1.000010",                                           &value)); @@ -270,78 +278,72 @@ run (void *cls)    ts = GNUNET_TIME_timestamp_get ();    deadline = GNUNET_TIME_timestamp_get (); -  //DENOMINATION    { -    //PAIR KEY LIST      new_dkp = GNUNET_new_array (MELT_NEW_COINS, -                              struct DenomKeyPair *); -    //PUBLIC KEY LIST +                                struct DenomKeyPair *);      new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS,                                         struct TALER_DenominationPublicKey); -    //REFRESH REVEAL COIN LIST      revealed_coins        = GNUNET_new_array (MELT_NEW_COINS,                            struct TALER_EXCHANGEDB_RefreshRevealedCoin);      for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) -      { -        struct GNUNET_TIME_Timestamp now; -        struct TALER_BlindedRsaPlanchet *rp; -        struct TALER_BlindedPlanchet *bp; - -        now = GNUNET_TIME_timestamp_get (); -        //5 KEY PAIR -        new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, -                                              now, -                                              &value, -                                              &fees); -        GNUNET_assert (NULL != new_dkp[cnt]); -        new_denom_pubs[cnt] = new_dkp[cnt]->pub; -        ccoin = &revealed_coins[cnt]; -        bp = &ccoin->blinded_planchet; -        bp->cipher = TALER_DENOMINATION_RSA; -        rp = &bp->details.rsa_blinded_planchet; -        rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( -                                                                      GNUNET_CRYPTO_QUALITY_WEAK, -                                                                      (RSA_KEY_SIZE / 8) - 1); -        rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); -        GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, -                                    rp->blinded_msg, -                                    rp->blinded_msg_size); -        TALER_denom_pub_hash (&new_dkp[cnt]->pub, -                              &ccoin->h_denom_pub); -        ccoin->exchange_vals = alg_values; -        TALER_coin_ev_hash (bp, -                            &ccoin->h_denom_pub, -                            &ccoin->coin_envelope_hash); -        GNUNET_assert (GNUNET_OK == +    { +      struct GNUNET_TIME_Timestamp now; +      struct TALER_BlindedRsaPlanchet *rp; +      struct TALER_BlindedPlanchet *bp; + +      now = GNUNET_TIME_timestamp_get (); +      new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, +                                            now, +                                            &value, +                                            &fees); +      GNUNET_assert (NULL != new_dkp[cnt]); +      new_denom_pubs[cnt] = new_dkp[cnt]->pub; +      ccoin = &revealed_coins[cnt]; +      bp = &ccoin->blinded_planchet; +      bp->cipher = TALER_DENOMINATION_RSA; +      rp = &bp->details.rsa_blinded_planchet; +      rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( +        GNUNET_CRYPTO_QUALITY_WEAK, +        (RSA_KEY_SIZE / 8) - 1); +      rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size); +      GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, +                                  rp->blinded_msg, +                                  rp->blinded_msg_size); +      TALER_denom_pub_hash (&new_dkp[cnt]->pub, +                            &ccoin->h_denom_pub); +      ccoin->exchange_vals = alg_values; +      TALER_coin_ev_hash (bp, +                          &ccoin->h_denom_pub, +                          &ccoin->coin_envelope_hash); +      GNUNET_assert (GNUNET_OK ==                       TALER_denom_sign_blinded (&ccoin->coin_sig,                                                 &new_dkp[cnt]->priv,                                                 true,                                                 bp)); -        GNUNET_assert (GNUNET_OK == -                       TALER_coin_ev_hash (bp, -                                           &cbc.denom_pub_hash, -                                           &cbc.h_coin_envelope)); -        GNUNET_assert ( -                       GNUNET_OK == -                       TALER_denom_sign_blinded ( -                                                 &cbc.sig, -                                                 &new_dkp[cnt]->priv, -                                                 false, -                                                 bp)); -      } +      GNUNET_assert (GNUNET_OK == +                     TALER_coin_ev_hash (bp, +                                         &cbc.denom_pub_hash, +                                         &cbc.h_coin_envelope)); +      GNUNET_assert ( +        GNUNET_OK == +        TALER_denom_sign_blinded ( +          &cbc.sig, +          &new_dkp[cnt]->priv, +          false, +          bp)); +    }    }    perm = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_NONCE,                                         NUM_ROWS); -  // begin    FAILIF (GNUNET_OK !=            plugin->start (plugin->cls,                           "Transaction")); -  for (unsigned int j=0; j< NUM_ROWS; j++) +  for (unsigned int j = 0; j< NUM_ROWS; j++)    {      unsigned int i = perm[j]; -    unsigned int k = (unsigned int)rand()%5; +    unsigned int k = (unsigned int) rand () % 5;      if (i >= ROUNDS)        i = ROUNDS; /* throw-away slot, do not keep around */      RND_BLK (&coin_pub); @@ -350,8 +352,6 @@ run (void *cls)      RND_BLK (&depos[i].coin.coin_pub);      TALER_denom_pub_hash (&new_dkp[k]->pub,                            &depos[i].coin.denom_pub_hash); -    // TALER_denom_pub_hash (&dkp->pub, -    //                    &ref.coin.denom_pub_hash);      GNUNET_assert (GNUNET_OK ==                     TALER_denom_sig_unblind (&depos[i].coin.denom_sig,                                              &cbc.sig, @@ -369,15 +369,15 @@ run (void *cls)      depos[i].receiver_wire_account =        "payto://iban/DE67830654080004822650?receiver-name=Test";      TALER_merchant_wire_signature_hash ( -                                        "payto://iban/DE67830654080004822650?receiver-name=Test", -                                        &depos[i].wire_salt, -                                        &h_wire_wt); +      "payto://iban/DE67830654080004822650?receiver-name=Test", +      &depos[i].wire_salt, +      &h_wire_wt);      depos[i].timestamp = ts; -      uint64_t known_coin_id; -    {//ENSURE_COIN_KNOWN - +    uint64_t known_coin_id; +    {        struct TALER_DenominationHashP dph;        struct TALER_AgeCommitmentHash agh; +        FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=                plugin->ensure_coin_known (plugin->cls,                                           &depos[i].coin, @@ -385,9 +385,9 @@ run (void *cls)                                           &dph,                                           &agh));      } -    /*STORE INTO DEPOSIT*/      {        struct GNUNET_TIME_Timestamp now; +        now = GNUNET_TIME_timestamp_get ();        FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=                plugin->insert_deposit (plugin->cls, @@ -399,12 +399,13 @@ run (void *cls)        bool refund_ok;        bool gone;        bool conflict; -      unsigned int refund_percent=0; -      switch (refund_percent){ -      case 2 ://100% refund +      unsigned int refund_percent = 0; +      switch (refund_percent) +      { +      case 2: // 100% refund          ref[i].coin = depos[i].coin;          ref[i].details.merchant_pub = depos[i].merchant_pub; -        RND_BLK(&ref[i].details.merchant_sig); +        RND_BLK (&ref[i].details.merchant_sig);          ref[i].details.h_contract_terms = depos[i].h_contract_terms;          ref[i].coin.coin_pub = depos[i].coin.coin_pub;          ref[i].details.rtransaction_id = i; @@ -420,58 +421,58 @@ run (void *cls)                                     &gone,                                     &conflict));          break; -    case 1 ://10% refund -      if (count < (NUM_ROWS/10)) -      { -        ref[i].coin = depos[i].coin; -        ref[i].details.merchant_pub = depos[i].merchant_pub; -        RND_BLK(&ref[i].details.merchant_sig); -        ref[i].details.h_contract_terms = depos[i].h_contract_terms; -        ref[i].coin.coin_pub = depos[i].coin.coin_pub; -        ref[i].details.rtransaction_id = i; -        ref[i].details.refund_amount = value; -        ref[i].details.refund_fee = fees.refund; -      } -      else -      { +      case 1:// 10% refund +        if (count < (NUM_ROWS / 10)) +        { +          ref[i].coin = depos[i].coin; +          ref[i].details.merchant_pub = depos[i].merchant_pub; +          RND_BLK (&ref[i].details.merchant_sig); +          ref[i].details.h_contract_terms = depos[i].h_contract_terms; +          ref[i].coin.coin_pub = depos[i].coin.coin_pub; +          ref[i].details.rtransaction_id = i; +          ref[i].details.refund_amount = value; +          ref[i].details.refund_fee = fees.refund; +        } +        else +        { +          ref[i].coin = depos[i].coin; +          RND_BLK (&ref[i].details.merchant_pub); +          RND_BLK (&ref[i].details.merchant_sig); +          RND_BLK (&ref[i].details.h_contract_terms); +          RND_BLK (&ref[i].coin.coin_pub); +          ref[i].details.rtransaction_id = i; +          ref[i].details.refund_amount = value; +          ref[i].details.refund_fee = fees.refund; +        } +        FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != +                plugin->do_refund (plugin->cls, +                                   &ref[i], +                                   &fees.deposit, +                                   known_coin_id, +                                   ¬_found, +                                   &refund_ok, +                                   &gone, +                                   &conflict)); +        count++; +        break; +      case 0:// no refund          ref[i].coin = depos[i].coin; -        RND_BLK(&ref[i].details.merchant_pub); -        RND_BLK(&ref[i].details.merchant_sig); -        RND_BLK(&ref[i].details.h_contract_terms); -        RND_BLK(&ref[i].coin.coin_pub); +        RND_BLK (&ref[i].details.merchant_pub); +        RND_BLK (&ref[i].details.merchant_sig); +        RND_BLK (&ref[i].details.h_contract_terms); +        RND_BLK (&ref[i].coin.coin_pub);          ref[i].details.rtransaction_id = i;          ref[i].details.refund_amount = value;          ref[i].details.refund_fee = fees.refund; -      } -      FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != -              plugin->do_refund (plugin->cls, -                                 &ref[i], -                                 &fees.deposit, -                                 known_coin_id, -                                 ¬_found, -                                 &refund_ok, -                                 &gone, -                                 &conflict)); -      count++; -      break; -    case 0://no refund -      ref[i].coin=depos[i].coin; -      RND_BLK(&ref[i].details.merchant_pub); -      RND_BLK(&ref[i].details.merchant_sig); -      RND_BLK(&ref[i].details.h_contract_terms); -      RND_BLK(&ref[i].coin.coin_pub); -      ref[i].details.rtransaction_id = i; -      ref[i].details.refund_amount = value; -      ref[i].details.refund_fee = fees.refund; -      FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != -              plugin->do_refund (plugin->cls, -                                 &ref[i], -                                 &fees.deposit, -                                 known_coin_id, -                                 ¬_found, -                                 &refund_ok, -                                 &gone, -                                 &conflict)); +        FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != +                plugin->do_refund (plugin->cls, +                                   &ref[i], +                                   &fees.deposit, +                                   known_coin_id, +                                   ¬_found, +                                   &refund_ok, +                                   &gone, +                                   &conflict));          break;        }/* END OF SWITCH CASE */      } @@ -480,7 +481,6 @@ run (void *cls)    }    /* End of benchmark setup */    GNUNET_free (perm); -  // commit    FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=            plugin->commit (plugin->cls));    for (unsigned int r = 0; r < ROUNDS; r++) @@ -500,7 +500,8 @@ run (void *cls)      times = GNUNET_TIME_relative_add (times,                                        duration);      duration_sq = duration.rel_value_us * duration.rel_value_us; -    GNUNET_assert (duration_sq / duration.rel_value_us == duration.rel_value_us); +    GNUNET_assert (duration_sq / duration.rel_value_us == +                   duration.rel_value_us);      GNUNET_assert (sqrs + duration_sq >= sqrs);      sqrs += duration_sq;    } @@ -514,10 +515,10 @@ run (void *cls)                                         ROUNDS);      avg_dbl = avg.rel_value_us;      variance = sqrs - (avg_dbl * avg_dbl * ROUNDS); -    fprintf(stdout, -            "%8llu ± %6.0f\n", -            (unsigned long long) avg.rel_value_us, -            sqrt (variance / (ROUNDS-1))); +    fprintf (stdout, +             "%8llu ± %6.0f\n", +             (unsigned long long) avg.rel_value_us, +             sqrt (variance / (ROUNDS - 1)));    }    result = 0;  drop: @@ -540,12 +541,12 @@ cleanup:         cnt++)      destroy_denom_key_pair (new_dkp[cnt]);    GNUNET_free (new_dkp); -  for (unsigned int i=0; i< ROUNDS +1 ; i++) -    { -      TALER_denom_sig_free (&depos[i].coin.denom_sig); -    } -  GNUNET_free(depos); -  GNUNET_free(ref); +  for (unsigned int i = 0; i< ROUNDS + 1; i++) +  { +    TALER_denom_sig_free (&depos[i].coin.denom_sig); +  } +  GNUNET_free (depos); +  GNUNET_free (ref);    TALER_EXCHANGEDB_plugin_unload (plugin);    plugin = NULL;  } @@ -557,7 +558,6 @@ main (int argc,  {    const char *plugin_name;    char *config_filename; -  char *testname;    struct GNUNET_CONFIGURATION_Handle *cfg;    (void) argc; @@ -571,15 +571,17 @@ main (int argc,                      "WARNING",                      NULL);    plugin_name++; -  (void) GNUNET_asprintf (&testname, -                          "test-exchange-db-%s", -                          plugin_name); -  (void) GNUNET_asprintf (&config_filename, -                          "%s.conf", -                          testname); -  fprintf (stdout, -           "Using config: %s\n", -           config_filename); +  { +    char *testname; + +    GNUNET_asprintf (&testname, +                     "test-exchange-db-%s", +                     plugin_name); +    GNUNET_asprintf (&config_filename, +                     "%s.conf", +                     testname); +    GNUNET_free (testname); +  }    cfg = GNUNET_CONFIGURATION_create ();    if (GNUNET_OK !=        GNUNET_CONFIGURATION_parse (cfg, @@ -587,16 +589,14 @@ main (int argc,    {      GNUNET_break (0);      GNUNET_free (config_filename); -    GNUNET_free (testname);      return 2;    }    GNUNET_SCHEDULER_run (&run,                          cfg);    GNUNET_CONFIGURATION_destroy (cfg);    GNUNET_free (config_filename); -  GNUNET_free (testname);    return result;  } -/* end of test_exchangedb_by_j.c */ +/* end of perf_select_refunds_by_coin.c */ diff --git a/src/exchangedb/pg_aggregate.c b/src/exchangedb/pg_aggregate.c index f1c4d677..6e94cbeb 100644 --- a/src/exchangedb/pg_aggregate.c +++ b/src/exchangedb/pg_aggregate.c @@ -1,6 +1,6 @@  /*     This file is part of TALER -   Copyright (C) 2022 Taler Systems SA +   Copyright (C) 2022, 2023 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 @@ -72,26 +72,16 @@ TEH_PG_aggregate (    now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (),                                           pg->aggregator_shift); -    /* Used in #postgres_aggregate() */ +  /* Used in #postgres_aggregate() */    PREPARE (pg,             "aggregate", -           "WITH rdy AS (" /* find deposits ready by merchant */ -           "  SELECT" -           "    coin_pub" -           "    FROM deposits_for_matching" -           "    WHERE refund_deadline<$1" /* filter by shard, only actually executable deposits */ -           "      AND merchant_pub=$2" /* filter by target merchant */ -           "    ORDER BY refund_deadline ASC" /* ordering is not critical */ -           "    LIMIT " -           TALER_QUOTE (TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT) /* limits transaction size */ -           " )" -           " ,dep AS (" /* restrict to our merchant and account and mark as done */ +           "WITH dep AS (" /* restrict to our merchant and account and mark as done */             "  UPDATE deposits"             "     SET done=TRUE" -           "   WHERE coin_pub IN (SELECT coin_pub FROM rdy)" -           "     AND merchant_pub=$2" /* theoretically, same coin could be spent at another merchant */ +           "   WHERE NOT (done OR policy_blocked)" /* only actually executable deposits */ +           "     AND refund_deadline<$1" /* filter by shard */ +           "     AND merchant_pub=$2" /* filter by target merchant */             "     AND wire_target_h_payto=$3" /* merchant could have a 2nd bank account */ -           "     AND done=FALSE" /* theoretically, same coin could be spend at the same merchant a 2nd time */             "   RETURNING"             "     deposit_serial_id"             "    ,coin_pub" diff --git a/src/exchangedb/pg_batch2_reserves_in_insert.c b/src/exchangedb/pg_batch2_reserves_in_insert.c deleted file mode 100644 index 1ef9045d..00000000 --- a/src/exchangedb/pg_batch2_reserves_in_insert.c +++ /dev/null @@ -1,914 +0,0 @@ -/* -   This file is part of TALER -   Copyright (C) 2022 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 exchangedb/pg_batch2_reserves_in_insert.c - * @brief Implementation of the reserves_in_insert function for Postgres - * @author Joseph Xu - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_batch2_reserves_in_insert.h" -#include "pg_helper.h" -#include "pg_start.h" -#include "pg_rollback.h" -#include "pg_start_read_committed.h" -#include "pg_commit.h" -#include "pg_reserves_get.h" -#include "pg_reserves_update.h" -#include "pg_setup_wire_target.h" -#include "pg_event_notify.h" -#include "pg_preflight.h" - -/** - * Generate event notification for the reserve change. - * - * @param reserve_pub reserve to notfiy on - */ -static char * -compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) -{ -  struct TALER_ReserveEventP rep = { -    .header.size = htons (sizeof (rep)), -    .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), -    .reserve_pub = *reserve_pub -  }; - -  return GNUNET_PG_get_event_notify_channel (&rep.header); -} - - -static enum GNUNET_DB_QueryStatus -insert1(struct PostgresClosure *pg, -        const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1], -        struct GNUNET_TIME_Timestamp expiry, -        struct GNUNET_TIME_Timestamp gc, -        struct TALER_PaytoHashP h_payto, -        char *const * notify_s, -        struct GNUNET_TIME_Timestamp reserve_expiration, -        bool *transaction_duplicate, -        bool *conflict, -        uint64_t *reserve_uuid, -        enum GNUNET_DB_QueryStatus results[1]) -{ -  enum GNUNET_DB_QueryStatus qs2; -  PREPARE (pg, -           "batch1_reserve_create", -           "SELECT " -           " out_reserve_found AS conflicted" -           ",transaction_duplicate" -           ",ruuid AS reserve_uuid" -           " FROM exchange_do_batch_reserves_in_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); - -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), -      TALER_PQ_query_param_amount (reserves[0].balance), -      GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[0].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s[0]), -      GNUNET_PQ_query_param_end -    }; - -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  &conflict[0]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  &transaction_duplicate[0]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    &reserve_uuid[0]), -      GNUNET_PQ_result_spec_end -    }; - - -    TALER_payto_hash (reserves[0].sender_account_details, -                      &h_payto); - -    qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "batch1_reserve_create", -                                                    params, -                                                    rs); - -    if (qs2 < 0) -      { -        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                    "Failed to create reserves 1(%d)\n", -                    qs2); -        results[0] = qs2; -        return qs2; -      } -    GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2); -    if ((! conflict[0]) && transaction_duplicate[0]) -      { -        GNUNET_break (0); -        TEH_PG_rollback (pg); -        results[0] = GNUNET_DB_STATUS_HARD_ERROR; -        return GNUNET_DB_STATUS_HARD_ERROR; -      } -    results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -    return qs2; -} - - - -static enum GNUNET_DB_QueryStatus -insert2 (struct PostgresClosure *pg, -         const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2], -         struct GNUNET_TIME_Timestamp expiry, -         struct GNUNET_TIME_Timestamp gc, -         struct TALER_PaytoHashP h_payto, -         char *const*notify_s, -         struct GNUNET_TIME_Timestamp reserve_expiration, -         bool *transaction_duplicate, -         bool *conflict, -         uint64_t *reserve_uuid, -         enum GNUNET_DB_QueryStatus results[1]) -{ -  enum GNUNET_DB_QueryStatus qs1; -  PREPARE (pg, -           "batch2_reserve_create", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",out_reserve_found2 AS conflicted2" -           ",transaction_duplicate" -           ",transaction_duplicate2" -           ",ruuid AS reserve_uuid" -           ",ruuid2 AS reserve_uuid2" -           " FROM exchange_do_batch2_reserves_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22);"); - -    struct GNUNET_PQ_QueryParam params[] = { - -      GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), -      TALER_PQ_query_param_amount (reserves[0].balance), -      GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[0].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s[0]), -      GNUNET_PQ_query_param_string (notify_s[1]), - -      GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), -      TALER_PQ_query_param_amount (reserves[1].balance), -      GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[1].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_end -    }; -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  &conflict[0]), -      GNUNET_PQ_result_spec_bool ("conflicted2", -                                  &conflict[1]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  &transaction_duplicate[0]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate2", -                                  &transaction_duplicate[1]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    &reserve_uuid[0]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", -                                    &reserve_uuid[1]), -      GNUNET_PQ_result_spec_end -    }; - -    TALER_payto_hash (reserves[0].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[1].sender_account_details, -                      &h_payto); - - -    qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "batch2_reserve_create", -                                                    params, -                                                    rs); -    if (qs1 < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves 2(%d)\n", -                  qs1); -      results[0]=qs1; -      return qs1; -    } - -    GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); -         /*   results[i] = (transaction_duplicate) -      ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS -      : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - -    if ( -        ((! conflict[0]) && (transaction_duplicate[0])) -        ||((! conflict[1]) && (transaction_duplicate[1])) -        ) -   { -     GNUNET_break (0); -     TEH_PG_rollback (pg); //ROLLBACK -     results[0] = GNUNET_DB_STATUS_HARD_ERROR; -     return GNUNET_DB_STATUS_HARD_ERROR; -   } -    results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -    return qs1; -} - - -static enum GNUNET_DB_QueryStatus -insert4 (struct PostgresClosure *pg, -         const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4], -         struct GNUNET_TIME_Timestamp expiry, -         struct GNUNET_TIME_Timestamp gc, -         struct TALER_PaytoHashP h_payto, -         char *const*notify_s, -         struct GNUNET_TIME_Timestamp reserve_expiration, -         bool *transaction_duplicate, -         bool *conflict, -         uint64_t *reserve_uuid, -         enum GNUNET_DB_QueryStatus results[1]) -{ -  enum GNUNET_DB_QueryStatus qs3; -  PREPARE (pg, -           "batch4_reserve_create", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",out_reserve_found2 AS conflicted2" -           ",out_reserve_found3 AS conflicted3" -           ",out_reserve_found4 AS conflicted4" -           ",transaction_duplicate" -           ",transaction_duplicate2" -           ",transaction_duplicate3" -           ",transaction_duplicate4" -           ",ruuid AS reserve_uuid" -           ",ruuid2 AS reserve_uuid2" -           ",ruuid3 AS reserve_uuid3" -           ",ruuid4 AS reserve_uuid4" -           " FROM exchange_do_batch4_reserves_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42);"); - -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), -      TALER_PQ_query_param_amount (reserves[0].balance), -      GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[0].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s[0]), -      GNUNET_PQ_query_param_string (notify_s[1]), -      GNUNET_PQ_query_param_string (notify_s[2]), -      GNUNET_PQ_query_param_string (notify_s[3]), - -      GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), -      TALER_PQ_query_param_amount (reserves[1].balance), -      GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[1].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), -      TALER_PQ_query_param_amount (reserves[2].balance), -      GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[2].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), -      TALER_PQ_query_param_amount (reserves[3].balance), -      GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[3].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_end -    }; - -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  &conflict[0]), -      GNUNET_PQ_result_spec_bool ("conflicted2", -                                  &conflict[1]), -      GNUNET_PQ_result_spec_bool ("conflicted3", -                                  &conflict[2]), -      GNUNET_PQ_result_spec_bool ("conflicted4", -                                  &conflict[3]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  &transaction_duplicate[0]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate2", -                                  &transaction_duplicate[1]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate3", -                                  &transaction_duplicate[2]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate4", -                                  &transaction_duplicate[3]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    &reserve_uuid[0]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", -                                    &reserve_uuid[1]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", -                                    &reserve_uuid[2]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", -                                    &reserve_uuid[3]), -      GNUNET_PQ_result_spec_end -    }; - -    TALER_payto_hash (reserves[0].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[1].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[2].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[3].sender_account_details, -                      &h_payto); - -    qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "batch4_reserve_create", -                                                    params, -                                                    rs); -    if (qs3 < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves4 (%d)\n", -                  qs3); -      results[0] = qs3; -      return qs3; -    } - -   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); - -    if ( -        ((! conflict[0]) && (transaction_duplicate[0])) -        ||((! conflict[1]) && (transaction_duplicate[1])) -        ||((! conflict[2]) && (transaction_duplicate[2])) -        ||((! conflict[3]) && (transaction_duplicate[3])) -        ) -   { -     GNUNET_break (0); -     TEH_PG_rollback (pg); -     results[0] = GNUNET_DB_STATUS_HARD_ERROR; -     return GNUNET_DB_STATUS_HARD_ERROR; -   } -    results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -    return qs3; -} - - -static enum GNUNET_DB_QueryStatus -insert8 (struct PostgresClosure *pg, -         const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8], -         struct GNUNET_TIME_Timestamp expiry, -         struct GNUNET_TIME_Timestamp gc, -         struct TALER_PaytoHashP h_payto, -         char *const*notify_s, -         struct GNUNET_TIME_Timestamp reserve_expiration, -         bool *transaction_duplicate, -         bool *conflict, -         uint64_t *reserve_uuid, -         enum GNUNET_DB_QueryStatus results[1]) -{ -  enum GNUNET_DB_QueryStatus qs3; -  PREPARE (pg, -           "batch8_reserve_create", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",out_reserve_found2 AS conflicted2" -           ",out_reserve_found3 AS conflicted3" -           ",out_reserve_found4 AS conflicted4" -           ",out_reserve_found5 AS conflicted5" -           ",out_reserve_found6 AS conflicted6" -           ",out_reserve_found7 AS conflicted7" -           ",out_reserve_found8 AS conflicted8" -           ",transaction_duplicate" -           ",transaction_duplicate2" -           ",transaction_duplicate3" -           ",transaction_duplicate4" -           ",transaction_duplicate5" -           ",transaction_duplicate6" -           ",transaction_duplicate7" -           ",transaction_duplicate8" -           ",ruuid AS reserve_uuid" -           ",ruuid2 AS reserve_uuid2" -           ",ruuid3 AS reserve_uuid3" -           ",ruuid4 AS reserve_uuid4" -           ",ruuid5 AS reserve_uuid5" -           ",ruuid6 AS reserve_uuid6" -           ",ruuid7 AS reserve_uuid7" -           ",ruuid8 AS reserve_uuid8" -           " FROM exchange_do_batch8_reserves_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$80,$81,$82);"); - -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), -      TALER_PQ_query_param_amount (reserves[0].balance), -      GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[0].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s[0]), -      GNUNET_PQ_query_param_string (notify_s[1]), -      GNUNET_PQ_query_param_string (notify_s[2]), -      GNUNET_PQ_query_param_string (notify_s[3]), -      GNUNET_PQ_query_param_string (notify_s[4]), -      GNUNET_PQ_query_param_string (notify_s[5]), -      GNUNET_PQ_query_param_string (notify_s[6]), -      GNUNET_PQ_query_param_string (notify_s[7]), - -      GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), -      TALER_PQ_query_param_amount (reserves[1].balance), -      GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[1].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), -      TALER_PQ_query_param_amount (reserves[2].balance), -      GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[2].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), -      TALER_PQ_query_param_amount (reserves[3].balance), -      GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[3].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference), -      TALER_PQ_query_param_amount (reserves[4].balance), -      GNUNET_PQ_query_param_string (reserves[4].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[4].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference), -      TALER_PQ_query_param_amount (reserves[5].balance), -      GNUNET_PQ_query_param_string (reserves[5].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[5].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference), -      TALER_PQ_query_param_amount (reserves[6].balance), -      GNUNET_PQ_query_param_string (reserves[6].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[6].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference), -      TALER_PQ_query_param_amount (reserves[7].balance), -      GNUNET_PQ_query_param_string (reserves[7].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[7].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_end -    }; - -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  &conflict[0]), -      GNUNET_PQ_result_spec_bool ("conflicted2", -                                  &conflict[1]), -      GNUNET_PQ_result_spec_bool ("conflicted3", -                                  &conflict[2]), -      GNUNET_PQ_result_spec_bool ("conflicted4", -                                  &conflict[3]), -      GNUNET_PQ_result_spec_bool ("conflicted5", -                                  &conflict[4]), -      GNUNET_PQ_result_spec_bool ("conflicted6", -                                  &conflict[5]), -      GNUNET_PQ_result_spec_bool ("conflicted7", -                                  &conflict[6]), -      GNUNET_PQ_result_spec_bool ("conflicted8", -                                  &conflict[7]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  &transaction_duplicate[0]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate2", -                                  &transaction_duplicate[1]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate3", -                                  &transaction_duplicate[2]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate4", -                                  &transaction_duplicate[3]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate5", -                                  &transaction_duplicate[4]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate6", -                                  &transaction_duplicate[5]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate7", -                                  &transaction_duplicate[6]), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate8", -                                  &transaction_duplicate[7]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    &reserve_uuid[0]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", -                                    &reserve_uuid[1]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", -                                    &reserve_uuid[2]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", -                                    &reserve_uuid[3]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid5", -                                    &reserve_uuid[4]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid6", -                                    &reserve_uuid[5]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid7", -                                    &reserve_uuid[6]), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid8", -                                    &reserve_uuid[7]), -      GNUNET_PQ_result_spec_end -    }; - -    TALER_payto_hash (reserves[0].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[1].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[2].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[3].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[4].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[5].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[6].sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserves[7].sender_account_details, -                      &h_payto); - -    qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "batch8_reserve_create", -                                                    params, -                                                    rs); -    if (qs3 < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves8 (%d)\n", -                  qs3); -      results[0]=qs3; -      return qs3; -    } - -   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); -   /*   results[i] = (transaction_duplicate) -      ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS -      : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - -    if ( -        ((! conflict[0]) && (transaction_duplicate[0])) -        ||((! conflict[1]) && (transaction_duplicate[1])) -        ||((! conflict[2]) && (transaction_duplicate[2])) -        ||((! conflict[3]) && (transaction_duplicate[3])) -        ||((! conflict[4]) && (transaction_duplicate[4])) -        ||((! conflict[5]) && (transaction_duplicate[5])) -        ||((! conflict[6]) && (transaction_duplicate[6])) -        ||((! conflict[7]) && (transaction_duplicate[7])) -        ) -   { -     GNUNET_break (0); -     TEH_PG_rollback (pg); -     results[0]=GNUNET_DB_STATUS_HARD_ERROR; -     return GNUNET_DB_STATUS_HARD_ERROR; -   } -    results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -    return qs3; -} - -enum GNUNET_DB_QueryStatus -TEH_PG_batch2_reserves_in_insert (void *cls, -                                  const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, -                                  unsigned int reserves_length, -                                  unsigned int batch_size, -                                  enum GNUNET_DB_QueryStatus *results) -{ -  struct PostgresClosure *pg = cls; -  enum GNUNET_DB_QueryStatus qs1; -  enum GNUNET_DB_QueryStatus qs2; -  enum GNUNET_DB_QueryStatus qs4; -  enum GNUNET_DB_QueryStatus qs5; -  struct GNUNET_TIME_Timestamp expiry; -  struct GNUNET_TIME_Timestamp gc; -  struct TALER_PaytoHashP h_payto; -  uint64_t reserve_uuid[reserves_length]; -  bool transaction_duplicate[reserves_length]; -  bool need_update = false; -  bool t_duplicate=false; -  struct GNUNET_TIME_Timestamp reserve_expiration -    = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); -  bool conflicts[reserves_length]; -  char *notify_s[reserves_length]; - -  if (GNUNET_OK != -      TEH_PG_preflight (pg)) -  { -    GNUNET_break (0); -    return GNUNET_DB_STATUS_HARD_ERROR; -  } - -  expiry = GNUNET_TIME_absolute_to_timestamp ( -    GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, -                              pg->idle_reserve_expiration_time)); -  gc = GNUNET_TIME_absolute_to_timestamp ( -    GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), -                              pg->legal_reserve_expiration_time)); -  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -              "Creating reserve %s with expiration in %s\n", -              TALER_B2S (&(reserves->reserve_pub)), -              GNUNET_STRINGS_relative_time_to_string ( -                pg->idle_reserve_expiration_time, -                GNUNET_NO)); - -  if (GNUNET_OK != -      TEH_PG_start_read_committed(pg, -                                  "READ_COMMITED")) -  { -    GNUNET_break (0); -    return GNUNET_DB_STATUS_HARD_ERROR; -  } - -  /* Optimistically assume this is a new reserve, create balance for the first -     time; we do this before adding the actual transaction to "reserves_in", -     as for a new reserve it can't be a duplicate 'add' operation, and as -     the 'add' operation needs the reserve entry as a foreign key. */ -  for (unsigned int i=0;i<reserves_length;i++) -  { -    const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i]; - -    notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub); -  } - -  unsigned int i=0; - -  while (i < reserves_length) -  { -    unsigned int bs = GNUNET_MIN (batch_size, -                                  reserves_length - i); -    if (bs >= 8) -    { -      qs1=insert8(pg, -                  &reserves[i], -                  expiry, -                  gc, -                  h_payto, -                  ¬ify_s[i], -                  reserve_expiration, -                  &transaction_duplicate[i], -                  &conflicts[i], -                  &reserve_uuid[i], -                  &results[i]); - -     if (qs1<0) -      { -        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                    "Failed to create reserve batch_8 (%d)\n", -                    qs1); -        return qs1; -      } -      need_update |= conflicts[i]; -      need_update |= conflicts[i+1]; -      need_update |= conflicts[i+2]; -      need_update |= conflicts[i+3]; -      need_update |= conflicts[i+4]; -      need_update |= conflicts[i+5]; -      need_update |= conflicts[i+6]; -      need_update |= conflicts[i+7]; -      t_duplicate |= transaction_duplicate[i]; -      t_duplicate |= transaction_duplicate[i+1]; -      t_duplicate |= transaction_duplicate[i+2]; -      t_duplicate |= transaction_duplicate[i+3]; -      t_duplicate |= transaction_duplicate[i+4]; -      t_duplicate |= transaction_duplicate[i+5]; -      t_duplicate |= transaction_duplicate[i+6]; -      t_duplicate |= transaction_duplicate[i+7]; -      i+=8; -      continue; -    } -    switch (bs) -      { -    case 7: -    case 6 : -    case 5: -    case 4 : -      qs4=insert4(pg, -                  &reserves[i], -                  expiry, -                  gc, -                  h_payto, -                  ¬ify_s[i], -                  reserve_expiration, -                  &transaction_duplicate[i], -                  &conflicts[i], -                  &reserve_uuid[i], -                  &results[i]); - -     if (qs4<0) -      { -        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                    "Failed to create reserve batch_4 (%d)\n", -                    qs4); -        return qs4; -      } -      need_update |= conflicts[i]; -      need_update |= conflicts[i+1]; -      need_update |= conflicts[i+2]; -      need_update |= conflicts[i+3]; -      t_duplicate |= transaction_duplicate[i]; -      t_duplicate |= transaction_duplicate[i+1]; -      t_duplicate |= transaction_duplicate[i+2]; -      t_duplicate |= transaction_duplicate[i+3]; -      //  fprintf(stdout, "reserve_uuid : %ld %ld %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1], reserve_uuid[i+2], reserve_uuid[i+3]); -      i += 4; -      break; -    case 3: -    case 2: -      qs5=insert2(pg, -                  &reserves[i], -                  expiry, -                  gc, -                  h_payto, -                  ¬ify_s[i], -                  reserve_expiration, -                  &transaction_duplicate[i], -                  &conflicts[i], -                  &reserve_uuid[i], -                  &results[i]); -      if (qs5<0) -      { -        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                    "Failed to create reserve batch_2 (%d)\n", -                    qs5); -        return qs5; -      } -      need_update |= conflicts[i]; -      need_update |= conflicts[i+1]; -      t_duplicate |= transaction_duplicate[i]; -      t_duplicate |= transaction_duplicate[i+1]; -      results[i] = (t_duplicate) -      ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS -      : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -      //   fprintf(stdout, "reserve_uuid : %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1]); -      i += 2; -      break; -    case 1: -      qs2 = insert1(pg, -                    &reserves[i], -                    expiry, -                    gc, -                    h_payto, -                    ¬ify_s[i], -                    reserve_expiration, -                    &transaction_duplicate[i], -                    &conflicts[i], -                    &reserve_uuid[i], -                    &results[i]); -      if (qs2<0) -      { -        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                    "Failed to create reserve batch_1 (%d)\n)" -                    ,qs2); -        return qs2; -      } -      need_update |= conflicts[i]; -      t_duplicate |= transaction_duplicate[i]; -      //  fprintf(stdout, "reserve uuid : %ld c :%d t:%d\n", reserve_uuid[i], conflicts[i], transaction_duplicate[i]); -      i += 1; -      break; -    case 0: -      GNUNET_assert (0); -      break; -    } -  } /* end while */ -  // commit -  { -    enum GNUNET_DB_QueryStatus cs; - -    cs = TEH_PG_commit (pg); -    if (cs < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to commit\n"); -      return cs; -    } -  } -  if (! need_update) -  { -    goto exit; -  } -  // begin serializable -  { -    if (GNUNET_OK != -        TEH_PG_start (pg, -                      "reserve-insert-continued")) -    { -      GNUNET_break (0); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -  } - -  enum GNUNET_DB_QueryStatus qs3; -  PREPARE (pg, -           "reserves_update", -           "SELECT" -           " out_duplicate AS duplicate " -           "FROM exchange_do_batch_reserves_update" -           " ($1,$2,$3,$4,$5,$6,$7,$8);"); -  for (unsigned int i = 0; i<reserves_length; i++) -    { -      if (! conflicts[i]) -        continue; -      { -        bool duplicate; -        struct GNUNET_PQ_QueryParam params[] = { -          GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub), -          GNUNET_PQ_query_param_timestamp (&expiry), -          GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference), -          TALER_PQ_query_param_amount (reserves[i].balance), -          GNUNET_PQ_query_param_string (reserves[i].exchange_account_name), -          GNUNET_PQ_query_param_auto_from_type (&h_payto), -          GNUNET_PQ_query_param_string (notify_s[i]), -          GNUNET_PQ_query_param_end -        }; -        struct GNUNET_PQ_ResultSpec rs[] = { -          GNUNET_PQ_result_spec_bool ("duplicate", -                                      &duplicate), -          GNUNET_PQ_result_spec_end -        }; -        qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                        "reserves_update", -                                                        params, -                                                        rs); -        if (qs3<0) -          { -            GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                        "Failed to update reserves (%d)\n", -                        qs3); -            results[i] = qs3; -            return qs3; -          } -        results[i] = duplicate -          ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS -          : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -      } -    } - -  { -    enum GNUNET_DB_QueryStatus cs; - -    cs = TEH_PG_commit (pg); -    if (cs < 0) -      return cs; -  } - -exit: -  for (unsigned int i = 0; i<reserves_length; i++) -    GNUNET_free (notify_s[i]); - -  return reserves_length; -} diff --git a/src/exchangedb/pg_batch2_reserves_in_insert.h b/src/exchangedb/pg_batch2_reserves_in_insert.h deleted file mode 100644 index 3191f867..00000000 --- a/src/exchangedb/pg_batch2_reserves_in_insert.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -   This file is part of TALER -   Copyright (C) 2022 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 exchangedb/pg_batch2_reserves_in_insert.h - * @brief implementation of the batch2_reserves_in_insert function for Postgres - * @author Joseph XU - */ -#ifndef PG_BATCH2_RESERVES_IN_INSERT_H -#define PG_BATCH2_RESERVES_IN_INSERT_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" -enum GNUNET_DB_QueryStatus -TEH_PG_batch2_reserves_in_insert (void *cls, -                                 const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, -                                 unsigned int reserves_length, -                                  unsigned int batch_size, -                                 enum GNUNET_DB_QueryStatus *results); - -#endif diff --git a/src/exchangedb/pg_batch4_reserves_in_insert.c b/src/exchangedb/pg_batch4_reserves_in_insert.c deleted file mode 100644 index 6536eb56..00000000 --- a/src/exchangedb/pg_batch4_reserves_in_insert.c +++ /dev/null @@ -1,595 +0,0 @@ - -/* -   This file is part of TALER -   Copyright (C) 2022 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 exchangedb/pg_batch_reserves_in_insert.c - * @brief Implementation of the reserves_in_insert function for Postgres - * @author Joseph Xu - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_batch_reserves_in_insert.h" -#include "pg_helper.h" -#include "pg_start.h" -#include "pg_rollback.h" -#include "pg_start_read_committed.h" -#include "pg_commit.h" -#include "pg_reserves_get.h" -#include "pg_reserves_update.h" -#include "pg_setup_wire_target.h" -#include "pg_event_notify.h" -#include "pg_preflight.h" - -/** - * Generate event notification for the reserve change. - * - * @param reserve_pub reserve to notfiy on - */ -static char * -compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) -{ -  struct TALER_ReserveEventP rep = { -    .header.size = htons (sizeof (rep)), -    .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), -    .reserve_pub = *reserve_pub -  }; - -  return GNUNET_PG_get_event_notify_channel (&rep.header); -} - - -static enum GNUNET_DB_QueryStatus -insert1(struct PostgresClosure *pg, -        const struct TALER_EXCHANGEDB_ReserveInInfo *reserve, -        struct GNUNET_TIME_Timestamp expiry, -        struct GNUNET_TIME_Timestamp gc, -        struct TALER_PaytoHashP h_payto, -        const char *notify_s, -        struct GNUNET_TIME_Timestamp reserve_expiration, -        bool *transaction_duplicate, -        bool *conflict, -        uint64_t *reserve_uuid) -{ -  enum GNUNET_DB_QueryStatus qs2; -  PREPARE (pg, -           "reserve_creates", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",transaction_duplicate" -           ",ruuid AS reserve_uuid" -           " FROM exchange_do_batch_reserves_in_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); - -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (&reserve->reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserve->wire_reference), -      TALER_PQ_query_param_amount (&reserve->balance), -      GNUNET_PQ_query_param_string (reserve->exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserve->execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve->sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s), -      GNUNET_PQ_query_param_end -    }; - -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  conflict), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  transaction_duplicate), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    reserve_uuid), -      GNUNET_PQ_result_spec_end -    }; - -    TALER_payto_hash (reserve->sender_account_details, -                      &h_payto); - -    /* Note: query uses 'on conflict do nothing' */ -    qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "reserve_creates", -                                                    params, -                                                    rs); - -    if (qs2 < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves (%d)\n", -                  qs2); -      return qs2; -    } -   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2); - -   if ((*conflict) && (*transaction_duplicate)) -   { -     GNUNET_break (0); -     TEH_PG_rollback (pg); -     return GNUNET_DB_STATUS_HARD_ERROR; -   } -   return qs2; -} - - - -static enum GNUNET_DB_QueryStatus -insert2 (struct PostgresClosure *pg, -         const struct TALER_EXCHANGEDB_ReserveInInfo *reserve0, -         const struct TALER_EXCHANGEDB_ReserveInInfo *reserve1, -         struct GNUNET_TIME_Timestamp expiry, -         struct GNUNET_TIME_Timestamp gc, -         struct TALER_PaytoHashP h_payto, -         const char *notify_s, -         struct GNUNET_TIME_Timestamp reserve_expiration, -         bool *transaction_duplicate, -         bool *transaction_duplicate2, -         bool *conflict, -         bool *conflict2, -         uint64_t *reserve_uuid, -         uint64_t *reserve_uuid2) -{ -  PREPARE (pg, -           "reserve_create", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",out_reserve_found2 AS conflicted2" -           ",transaction_duplicate" -           ",transaction_duplicate2" -           ",ruuid AS reserve_uuid" -           ",ruuid2 AS reserve_uuid2" -           " FROM exchange_do_batch2_reserves_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21);"); - -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (&reserve0->reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserve0->wire_reference), -      TALER_PQ_query_param_amount (&reserve0->balance), -      GNUNET_PQ_query_param_string (reserve0->exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserve0->execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve0->sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s), -      GNUNET_PQ_query_param_auto_from_type (&reserve1->reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserve1->wire_reference), -      TALER_PQ_query_param_amount (&reserve1->balance), -      GNUNET_PQ_query_param_string (reserve1->exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserve1->execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve1->sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_end -    }; - -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  conflict), -      GNUNET_PQ_result_spec_bool ("conflicted2", -                                  conflict2), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  transaction_duplicate), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate2", -                                  transaction_duplicate2), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    reserve_uuid), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", -                                    reserve_uuid2), -      GNUNET_PQ_result_spec_end -    }; - -    TALER_payto_hash (reserve0->sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserve1->sender_account_details, -                      &h_payto); - - -    qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "reserve_create", -                                                    params, -                                                    rs); -    if (qs1 < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves (%d)\n", -                  qs1); -      return qs1; -    } -    /* -   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); -   results[i] = (transaction_duplicate) -      ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS -      : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - -    if ((*conflict) && (*transaction_duplicate) ||((*conflict2) && (*transaction_duplicate2))) -   { -     GNUNET_break (0); -     TEH_PG_rollback (pg); -     return GNUNET_DB_STATUS_HARD_ERROR; -   } - -} - - -static enum GNUNET_DB_QueryStatus -insert4 (struct PostgresClosure *pg, -         const struct TALER_EXCHANGEDB_ReserveInInfo *reserve0, -         const struct TALER_EXCHANGEDB_ReserveInInfo *reserve1, -         const struct TALER_EXCHANGEDB_ReserveInInfo *reserve2, -         const struct TALER_EXCHANGEDB_ReserveInInfo *reserve3, -         struct GNUNET_TIME_Timestamp expiry, -         struct GNUNET_TIME_Timestamp gc, -         struct TALER_PaytoHashP h_payto, -         const char *notify_s, -         struct GNUNET_TIME_Timestamp reserve_expiration, -         bool *transaction_duplicate, -         bool *transaction_duplicate2, -         bool *transaction_duplicate3, -         bool *transaction_duplicate4, -         bool *conflict, -         bool *conflict2, -         bool *conflict3, -         bool *conflict4, -         uint64_t *reserve_uuid, -         uint64_t *reserve_uuid2, -         uint64_t *reserve_uuid3, -         uint64_t *reserve_uuid4) -{ -  PREPARE (pg, -           "reserve_create", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",out_reserve_found2 AS conflicted2" -           ",out_reserve_found3 AS conflicted3" -           ",out_reserve_found4 AS conflicted4" -           ",transaction_duplicate" -           ",transaction_duplicate2" -           ",transaction_duplicate3" -           ",transaction_duplicate4" -           ",ruuid AS reserve_uuid" -           ",ruuid2 AS reserve_uuid2" -           ",ruuid3 AS reserve_uuid3" -           ",ruuid4 AS reserve_uuid4" -           " FROM exchange_do_batch4_reserves_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39);"); - -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (&reserve0->reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserve0->wire_reference), -      TALER_PQ_query_param_amount (&reserve0->balance), -      GNUNET_PQ_query_param_string (reserve0->exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserve0->execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve0->sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s), - -      GNUNET_PQ_query_param_auto_from_type (&reserve1->reserve_pub), -      GNUNET_PQ_query_param_uint64 (&reserve1->wire_reference), -      TALER_PQ_query_param_amount (&reserve1->balance), -      GNUNET_PQ_query_param_string (reserve1->exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserve1->execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve1->sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (&reserve2->reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserve2->wire_reference), -      TALER_PQ_query_param_amount (&reserve2->balance), -      GNUNET_PQ_query_param_string (reserve2->exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserve2->execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve2->sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), - -      GNUNET_PQ_query_param_auto_from_type (&reserve3->reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserve3->wire_reference), -      TALER_PQ_query_param_amount (&reserve3->balance), -      GNUNET_PQ_query_param_string (reserve3->exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserve3->execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserve3->sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration) - -      GNUNET_PQ_query_param_end -    }; - -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  conflict), -      GNUNET_PQ_result_spec_bool ("conflicted2", -                                  conflict2), -      GNUNET_PQ_result_spec_bool ("conflicted3", -                                  conflict3), -      GNUNET_PQ_result_spec_bool ("conflicted4", -                                  conflict4), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  transaction_duplicate), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate2", -                                  transaction_duplicate2), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate3", -                                  transaction_duplicate3), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate4", -                                  transaction_duplicate4), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    reserve_uuid), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", -                                    reserve_uuid2), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", -                                    reserve_uuid3), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", -                                    reserve_uuid4), -      GNUNET_PQ_result_spec_end -    }; - -    TALER_payto_hash (reserve0->sender_account_details, -                      &h_payto); -    TALER_payto_hash (reserve1->sender_account_details, -                      &h_payto); - - -    qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "reserve_create", -                                                    params, -                                                    rs); -    if (qs1 < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves (%d)\n", -                  qs1); -      return qs1; -    } -    /* -   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); -   results[i] = (transaction_duplicate) -      ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS -      : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ - -    if ((*conflict) && (*transaction_duplicate) ||((*conflict2) && (*transaction_duplicate2))) -   { -     GNUNET_break (0); -     TEH_PG_rollback (pg); -     return GNUNET_DB_STATUS_HARD_ERROR; -   } - -} - - - -enum GNUNET_DB_QueryStatus -TEH_PG_batch2_reserves_in_insert (void *cls, -                                 const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, -                                 unsigned int reserves_length, -                                 enum GNUNET_DB_QueryStatus *results) -{ -  struct PostgresClosure *pg = cls; -  enum GNUNET_DB_QueryStatus qs1; -  enum GNUNET_DB_QueryStatus qs2; -  enum GNUNET_DB_QueryStatus qs4; -  enum GNUNET_DB_QueryStatus qs5; -  struct GNUNET_TIME_Timestamp expiry; -  struct GNUNET_TIME_Timestamp gc; -  struct TALER_PaytoHashP h_payto; -  uint64_t reserve_uuid[reserves_length]; -  bool conflicted; -  bool conflicted2; -  bool transaction_duplicate[reserves_length]; -  bool need_update = false; -  bool need_update2 = false; -  struct GNUNET_TIME_Timestamp reserve_expiration -    = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); -  bool conflicts[reserves_length]; -  char *notify_s[reserves_length]; - -  if (GNUNET_OK != -      TEH_PG_preflight (pg)) -  { -    GNUNET_break (0); -    return GNUNET_DB_STATUS_HARD_ERROR; -  } - -  expiry = GNUNET_TIME_absolute_to_timestamp ( -    GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, -                              pg->idle_reserve_expiration_time)); -  gc = GNUNET_TIME_absolute_to_timestamp ( -    GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), -                              pg->legal_reserve_expiration_time)); -  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -              "Creating reserve %s with expiration in %s\n", -              TALER_B2S (&(reserves->reserve_pub)), -              GNUNET_STRINGS_relative_time_to_string ( -                pg->idle_reserve_expiration_time, -                GNUNET_NO)); - -  { -    if (GNUNET_OK != -        TEH_PG_start_read_committed(pg, -                                   "READ_COMMITED")) -    { -      GNUNET_break (0); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -  } -  /* Optimistically assume this is a new reserve, create balance for the first -     time; we do this before adding the actual transaction to "reserves_in", -     as for a new reserve it can't be a duplicate 'add' operation, and as -     the 'add' operation needs the reserve entry as a foreign key. */ -  for (unsigned int i=0;i<reserves_length;i++) -  { -    const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i]; -    notify_s[i] = compute_notify_on_reserve (&reserve->reserve_pub); -  } - -  unsigned int i=0; - -  while (i < reserves_length) -  { -    if (reserves_length - i >= 4) -    { -      qs4=insert4(pg, -              &reserves[i], -              &reserves[i+2], -              &reserves[i+3], -              &reserves[i+4], -              expiry, -              gc, -              h_payto, -              ¬ify_s[i], -              reserve_expiration, -              &transaction_duplicate[i], -              &transaction_duplicate[i+1], -              &transaction_duplicate[i+2], -              &transaction_duplicate[i+3], -              &conflicts[i], -              &conflicts[i+1], -              &conflicts[i+2], -              &conflicts[i+3], -              &reserve_uuid[i], -              &reserve_uuid[i+1], -              &reserve_uuid[i+2], -              &reserve_uuid[i+3]); - -      need_update |= conflicts[i]; -      need_update |= conflicts[i+1]; -      need_update |= conflicts[i+2]; -      need_update |= conflicts[i+3]; -      i += 4; -      continue; -    } -    switch (reserves_length - i) -    { -    case 3: -    case 2: -      qs5=insert2(pg, -              &reserves[i], -              &reserves[i+1], -              expiry, -              gc, -              h_payto, -              notify_s[i], -              reserve_expiration, -              &transaction_duplicate[i], -              &transaction_duplicate[i+1], -              &conflicts[i], -              &conflicts[i+1], -              &reserve_uuid[i], -              &reserve_uuid[i+1]); -      need_update |= conflicts[i]; -      need_update |= conflicts[i+1]; -      i += 2; -      break; -    case 1: -      qs2 = insert1(pg, -                    &reserves[i], -                    expiry, -                    gc, -                    h_payto, -                    notify_s[i], -                    reserve_expiration, -                    &transaction_duplicate[i], -                    &conflicts[i], -                    &reserve_uuid[i]); -      need_update |= conflicts[i]; -      i += 1; -      break; -    case 0: -      GNUNET_assert (0); -      break; -    } -  } /* end while */ -  // commit -  { -    enum GNUNET_DB_QueryStatus cs; - -    cs = TEH_PG_commit (pg); -    if (cs < 0) -      return cs; -  } - -  if (!need_update ) -    goto exit; -  // begin serializable -  { -    if (GNUNET_OK != -        TEH_PG_start(pg, -                     "reserve-insert-continued")) -    { -      GNUNET_break (0); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -  } - -  enum GNUNET_DB_QueryStatus qs3; -  PREPARE (pg, -           "reserves_in_add_transaction", -           "CALL exchange_do_batch_reserves_update" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9);"); -  for (unsigned int i=0;i<reserves_length;i++) -  { -    if (! conflicts[i]) -      continue; -    { -      const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i]; -      struct GNUNET_PQ_QueryParam params[] = { -        GNUNET_PQ_query_param_auto_from_type (&reserve->reserve_pub), -        GNUNET_PQ_query_param_timestamp (&expiry), -        GNUNET_PQ_query_param_uint64 (&reserve->wire_reference), -        TALER_PQ_query_param_amount (&reserve->balance), -        GNUNET_PQ_query_param_string (reserve->exchange_account_name), -        GNUNET_PQ_query_param_bool (conflicted), -        GNUNET_PQ_query_param_auto_from_type (&h_payto), -        GNUNET_PQ_query_param_string (notify_s[i]), -        GNUNET_PQ_query_param_end -      }; - -      qs3 = GNUNET_PQ_eval_prepared_non_select (pg->conn, -                                                "reserves_in_add_transaction", -                                                params); -      if (qs3<0) -      { -        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                    "Failed to update reserves (%d)\n", -                    qs3); -        return qs3; -      } -    } -  } -  { -    enum GNUNET_DB_QueryStatus cs; - -    cs = TEH_PG_commit (pg); -    if (cs < 0) -      return cs; -  } - - exit: -  for (unsigned int i=0;i<reserves_length;i++) -    GNUNET_free (notify_s[i]); - -  return reserves_length; -} diff --git a/src/exchangedb/pg_batch_reserves_in_insert.c b/src/exchangedb/pg_batch_reserves_in_insert.c deleted file mode 100644 index f1e4a936..00000000 --- a/src/exchangedb/pg_batch_reserves_in_insert.c +++ /dev/null @@ -1,252 +0,0 @@ -/* -   This file is part of TALER -   Copyright (C) 2022 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 exchangedb/pg_batch_reserves_in_insert.c - * @brief Implementation of the reserves_in_insert function for Postgres - * @author Joseph Xu - */ -#include "platform.h" -#include "taler_error_codes.h" -#include "taler_dbevents.h" -#include "taler_pq_lib.h" -#include "pg_batch_reserves_in_insert.h" -#include "pg_helper.h" -#include "pg_start.h" -#include "pg_rollback.h" -#include "pg_start_read_committed.h" -#include "pg_commit.h" -#include "pg_reserves_get.h" -#include "pg_reserves_update.h" -#include "pg_setup_wire_target.h" -#include "pg_event_notify.h" -#include "pg_preflight.h" - - -/** - * Generate event notification for the reserve change. - * - * @param reserve_pub reserve to notfiy on - */ -static char * -compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub) -{ -  struct TALER_ReserveEventP rep = { -    .header.size = htons (sizeof (rep)), -    .header.type = htons (TALER_DBEVENT_EXCHANGE_RESERVE_INCOMING), -    .reserve_pub = *reserve_pub -  }; - -  return GNUNET_PG_get_event_notify_channel (&rep.header); -} - - -enum GNUNET_DB_QueryStatus -TEH_PG_batch_reserves_in_insert ( -  void *cls, -  const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, -  unsigned int reserves_length, -  enum GNUNET_DB_QueryStatus *results) -{ -  struct PostgresClosure *pg = cls; -  enum GNUNET_DB_QueryStatus qs1; -  struct GNUNET_TIME_Timestamp expiry; -  struct GNUNET_TIME_Timestamp gc; -  struct TALER_PaytoHashP h_payto; -  uint64_t reserve_uuid; -  struct GNUNET_TIME_Timestamp reserve_expiration -    = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); -  bool conflicts[reserves_length]; -  char *notify_s[reserves_length]; - -  if (GNUNET_OK != -      TEH_PG_preflight (pg)) -  { -    GNUNET_break (0); -    return GNUNET_DB_STATUS_HARD_ERROR; -  } -  PREPARE (pg, -           "reserve_create", -           "SELECT " -           "out_reserve_found AS conflicted" -           ",transaction_duplicate" -           ",ruuid AS reserve_uuid" -           " FROM exchange_do_batch_reserves_in_insert" -           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); -  expiry = GNUNET_TIME_absolute_to_timestamp ( -    GNUNET_TIME_absolute_add (reserves->execution_time.abs_time, -                              pg->idle_reserve_expiration_time)); -  gc = GNUNET_TIME_absolute_to_timestamp ( -    GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), -                              pg->legal_reserve_expiration_time)); -  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -              "Creating reserve %s with expiration in %s\n", -              TALER_B2S (reserves->reserve_pub), -              GNUNET_STRINGS_relative_time_to_string ( -                pg->idle_reserve_expiration_time, -                GNUNET_NO)); -  if (GNUNET_OK != -      TEH_PG_start_read_committed (pg, -                                   "READ_COMMITED")) -  { -    GNUNET_break (0); -    return GNUNET_DB_STATUS_HARD_ERROR; -  } -  /* Optimistically assume this is a new reserve, create balance for the first -     time; we do this before adding the actual transaction to "reserves_in", -     as for a new reserve it can't be a duplicate 'add' operation, and as -     the 'add' operation needs the reserve entry as a foreign key. */ -  for (unsigned int i = 0; i<reserves_length; i++) -  { -    const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i]; -    notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub); -  } -  bool need_update = false; -  for (unsigned int i = 0; i<reserves_length; i++) -  { -    bool conflicted; -    bool transaction_duplicate; - -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference), -      TALER_PQ_query_param_amount (reserves[i].balance), -      GNUNET_PQ_query_param_string (reserves[i].exchange_account_name), -      GNUNET_PQ_query_param_timestamp (&reserves[i].execution_time), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_string (reserves[i].sender_account_details), -      GNUNET_PQ_query_param_timestamp (&reserve_expiration), -      GNUNET_PQ_query_param_string (notify_s[i]), -      GNUNET_PQ_query_param_end -    }; -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_bool ("conflicted", -                                  &conflicted), -      GNUNET_PQ_result_spec_bool ("transaction_duplicate", -                                  &transaction_duplicate), -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    &reserve_uuid), -      GNUNET_PQ_result_spec_end -    }; - -    TALER_payto_hash (reserves[i].sender_account_details, -                      &h_payto); -    /* Note: query uses 'on conflict do nothing' */ -    qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "reserve_create", -                                                    params, -                                                    rs); -    if (qs1 < 0) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to create reserves (%d)\n", -                  qs1); -      results[i] = qs1; -      return qs1; -    } -    GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); -    conflicts[i] = conflicted; -    //   fprintf(stdout, "%d", conflicts[i]); -    if (conflicts[i] && transaction_duplicate) -    { -      GNUNET_break (0); -      results[i] = GNUNET_DB_STATUS_HARD_ERROR; -      TEH_PG_rollback (pg); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -    results[i] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -    need_update |= conflicted; -  } -  // commit -  { -    enum GNUNET_DB_QueryStatus cs; - -    cs = TEH_PG_commit (pg); -    if (cs < 0) -      return cs; -  } -  if (! need_update) -    goto exit; -  // begin serializable -  { -    if (GNUNET_OK != -        TEH_PG_start (pg, -                      "reserve-insert-continued")) -    { -      GNUNET_break (0); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -  } - -  enum GNUNET_DB_QueryStatus qs2; -  PREPARE (pg, -           "reserves_in_add_transaction", -           "SELECT" -           "  out_duplicate AS duplicate" -           " FROM exchange_do_batch_reserves_update" -           " ($1,$2,$3,$4,$5,$6,$7,$8);"); -  for (unsigned int i = 0; i<reserves_length; i++) -  { -    if (! conflicts[i]) -      continue; -    { -      bool duplicate; -      struct GNUNET_PQ_QueryParam params[] = { -        GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub), -        GNUNET_PQ_query_param_timestamp (&expiry), -        GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference), -        TALER_PQ_query_param_amount (reserves[i].balance), -        GNUNET_PQ_query_param_string (reserves[i].exchange_account_name), -        GNUNET_PQ_query_param_auto_from_type (&h_payto), -        GNUNET_PQ_query_param_string (notify_s[i]), -        GNUNET_PQ_query_param_end -      }; -      struct GNUNET_PQ_ResultSpec rs[] = { -        GNUNET_PQ_result_spec_bool ("duplicate", -                                    &duplicate), -        GNUNET_PQ_result_spec_end -      }; -      qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                      "reserves_in_add_transaction", -                                                      params, -                                                      rs); -      if (qs2 < 0) -      { -        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                    "Failed to update reserves (%d)\n", -                    qs2); -        results[i] = qs2; -        return qs2; -      } -      results[i] = duplicate -        ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS -        : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -    } -  } -  { -    enum GNUNET_DB_QueryStatus cs; - -    cs = TEH_PG_commit (pg); -    if (cs < 0) -      return cs; -  } -exit: -  for (unsigned int i = 0; i<reserves_length; i++) -    GNUNET_free (notify_s[i]); - -  return reserves_length; -} diff --git a/src/exchangedb/pg_batch_reserves_in_insert.h b/src/exchangedb/pg_batch_reserves_in_insert.h deleted file mode 100644 index 76679567..00000000 --- a/src/exchangedb/pg_batch_reserves_in_insert.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -   This file is part of TALER -   Copyright (C) 2022 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 exchangedb/pg_batch_reserves_in_insert.h - * @brief implementation of the batch_reserves_in_insert function for Postgres - * @author Christian Grothoff - */ -#ifndef PG_BATCH_RESERVES_IN_INSERT_H -#define PG_BATCH_RESERVES_IN_INSERT_H - -#include "taler_util.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" - - -enum GNUNET_DB_QueryStatus -TEH_PG_batch_reserves_in_insert (void *cls, -                              const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, -                              unsigned int reserves_length, -                                 enum GNUNET_DB_QueryStatus *results); - -#endif diff --git a/src/exchangedb/pg_get_link_data.c b/src/exchangedb/pg_get_link_data.c index 26225a13..a0795433 100644 --- a/src/exchangedb/pg_get_link_data.c +++ b/src/exchangedb/pg_get_link_data.c @@ -55,7 +55,7 @@ struct LinkDataContext    /**     * Status, set to #GNUNET_SYSERR on errors,     */ -  int status; +  enum GNUNET_GenericReturnValue status;  }; @@ -190,20 +190,18 @@ TEH_PG_get_link_data (void *cls,                         "%d%c",                         &percent_refund,                         &dummy)) ) -      { -        if (NULL != mode) -          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                      "Bad mode `%s' specified\n", -                      mode); -      } -      if (NULL==mode) -        percent_refund=0; +    { +      if (NULL != mode) +        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                    "Bad mode `%s' specified\n", +                    mode); +      percent_refund = 0; +    }    } -    switch (percent_refund)    {    case 0: -    query="get_link"; +    query = "get_link";      PREPARE (pg,               query,               "SELECT " @@ -225,7 +223,7 @@ TEH_PG_get_link_data (void *cls,               " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC");      break;    case 1: -    query="get_link_v1"; +    query = "get_link_v1";      PREPARE (pg,               query,               "WITH rc AS MATERIALIZED (" @@ -252,7 +250,7 @@ TEH_PG_get_link_data (void *cls,               " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC");      break;    case 2: -    query="get_link_v2"; +    query = "get_link_v2";      PREPARE (pg,               query,               "SELECT" @@ -300,5 +298,3 @@ TEH_PG_get_link_data (void *cls,      return GNUNET_DB_STATUS_HARD_ERROR;    return qs;  } - - diff --git a/src/exchangedb/pg_get_ready_deposit.c b/src/exchangedb/pg_get_ready_deposit.c index 73ac9e47..91151c61 100644 --- a/src/exchangedb/pg_get_ready_deposit.c +++ b/src/exchangedb/pg_get_ready_deposit.c @@ -1,6 +1,6 @@  /*     This file is part of TALER -   Copyright (C) 2022 Taler Systems SA +   Copyright (C) 2022, 2023 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 @@ -33,15 +33,16 @@ TEH_PG_get_ready_deposit (void *cls,                            struct TALER_MerchantPublicKeyP *merchant_pub,                            char **payto_uri)  { +  static int choose_mode = -2;    struct PostgresClosure *pg = cls; -  struct GNUNET_TIME_Absolute now = {0}; +  struct GNUNET_TIME_Absolute now +    = GNUNET_TIME_absolute_get ();    struct GNUNET_PQ_QueryParam params[] = {      GNUNET_PQ_query_param_absolute_time (&now),      GNUNET_PQ_query_param_uint64 (&start_shard_row),      GNUNET_PQ_query_param_uint64 (&end_shard_row),      GNUNET_PQ_query_param_end    }; -    struct GNUNET_PQ_ResultSpec rs[] = {      GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",                                            merchant_pub), @@ -49,181 +50,70 @@ TEH_PG_get_ready_deposit (void *cls,                                    payto_uri),      GNUNET_PQ_result_spec_end    }; - -  now = GNUNET_TIME_absolute_round_down (GNUNET_TIME_absolute_get (), -                                         pg->aggregator_shift); -  GNUNET_assert (start_shard_row < end_shard_row); -  GNUNET_assert (end_shard_row <= INT32_MAX); -  GNUNET_log (GNUNET_ERROR_TYPE_INFO, -              "Finding ready deposits by deadline %s (%llu)\n", -              GNUNET_TIME_absolute2s (now), -              (unsigned long long) now.abs_value_us); -  int choose_mode =-2;    const char *query;    if (-2 == choose_mode)    { -    const char *mode = getenv ("NEW_LOGIC"); +    const char *mode = getenv ("TALER_POSTGRES_GET_READY_LOGIC");      char dummy; +      if ( (NULL==mode) ||           (1 != sscanf (mode,                         "%d%c",                         &choose_mode,                         &dummy)) ) -      { -        if (NULL != mode) -          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                      "Bad mode `%s' specified\n", -                      mode); -      } -    if (NULL==mode) -      choose_mode=0; - - +    { +      if (NULL != mode) +        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                    "Bad mode `%s' specified\n", +                    mode); +      choose_mode = 0; +    }    }    switch (choose_mode)    {    case 0: -    query="deposits_get_ready"; +    query = "deposits_get_ready-v5";      PREPARE (pg,               query,               "SELECT"               " payto_uri"               ",merchant_pub" -             " FROM deposits_by_ready dbr" -             "  JOIN deposits dep" -             "    ON (dbr.coin_pub = dep.coin_pub AND" -             "        dbr.deposit_serial_id = dep.deposit_serial_id)" -             "  JOIN wire_targets wt" -             "    USING (wire_target_h_payto)" -             " WHERE dbr.wire_deadline<=$1" -             "   AND dbr.shard >= $2" -             "   AND dbr.shard <= $3" +             " FROM deposits dep" +             " JOIN wire_targets wt" +             "   USING (wire_target_h_payto)" +             " WHERE NOT (done OR policy_blocked)" +             "   AND dep.wire_deadline<=$1" +             "   AND dep.shard >= $2" +             "   AND dep.shard <= $3"               " ORDER BY " -             "   dbr.wire_deadline ASC" -             "  ,dbr.shard ASC" +             "   dep.wire_deadline ASC" +             "  ,dep.shard ASC"               " LIMIT 1;");      break;    case 1: -    query="deposits_get_ready_v1"; +    query = "deposits_get_ready-v6";      PREPARE (pg,               query,               "WITH rc AS MATERIALIZED ("               " SELECT" -             " coin_pub" -             ",deposit_serial_id" -             " FROM deposits_by_ready" -             " WHERE" -             " wire_deadline<=$1" -             " AND shard >= $2" -             " AND shard <= $3" -             " ORDER BY " -             "   wire_deadline ASC" -             "  ,shard ASC" -             "  LIMIT 1" -             ")" -             "SELECT" -             " wt.payto_uri" -             ",dep.merchant_pub" -             " FROM (" -             " SELECT" -             " wire_target_h_payto" -             ",merchant_pub" +             " merchant_pub" +             ",wire_target_h_payto"               " FROM deposits" -             " WHERE coin_pub=(SELECT coin_pub FROM rc)" -             " AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)" -             ") dep" -             "  JOIN wire_targets wt" -             "    ON (dep.wire_target_h_payto = wt.wire_target_h_payto)" -             ); - -    break; -  case 2: -    query = "stored_procedure_get_ready_deposit"; -    PREPARE (pg, -             query, -             "SELECT" -             " out_payto_uri AS payto_uri" -             ",out_merchant_pub AS merchant_pub" -             " FROM" -             " exchange_do_get_ready_deposit" -             " ($1, $2, $3) "); -    break; -  case 3: -    query="deposits_get_ready_v3"; -    PREPARE (pg, -             query, -             "WITH rc AS MATERIALIZED (" -             " SELECT" -             " coin_pub" -             ",deposit_serial_id" -             " FROM deposits_by_ready" -             " WHERE" -             " wire_deadline<=$1" -             " AND shard >= $2" -             " AND shard <= $3" -             " ORDER BY " -             "   wire_deadline ASC" +             " WHERE NOT (done OR policy_blocked)" +             "   AND wire_deadline<=$1" +             "   AND shard >= $2" +             "   AND shard <= $3" +             " ORDER BY wire_deadline ASC"               "  ,shard ASC"               "  LIMIT 1"               ")"               "SELECT"               " wt.payto_uri" -             ",dep.merchant_pub" -             " FROM (" -             " SELECT" -             " wire_target_h_payto" -             ",merchant_pub" -             ",coin_pub" -             " FROM deposits" -             " WHERE coin_pub=(SELECT coin_pub FROM rc)" -             " AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)" -             ") dep" -             "  JOIN wire_targets wt" -             "    ON (dep.wire_target_h_payto = wt.wire_target_h_payto)" -             "  JOIN rc" -             "    ON (dep.coin_pub=rc.coin_pub)" -             ); - -    break; -  case 4: -    query="deposits_get_ready_v4"; -    PREPARE (pg, -             query, -             "WITH rc AS MATERIALIZED (" -             " SELECT" -             " coin_pub" -             ",deposit_serial_id" -             " FROM deposits_by_ready" -             " WHERE" -             " wire_deadline<=$1" -             " AND shard >= $2" -             " AND shard <= $3" -             " ORDER BY " -             "   wire_deadline ASC" -             "  ,shard ASC" -             "  LIMIT 1" -             ")," -             "WITH rv AS MATERIALIZED (" -             " SELECT" -             " payto_uri" -             ",wire_target_h_payto" -             " FROM wire_targets" -             ")" -             "SELECT" -             " rv.payto_uri" -             ",dep.merchant_pub" -             " FROM (" -             " SELECT" -             " wire_target_h_payto" -             ",merchant_pub" -             " FROM deposits" -             " WHERE coin_pub=(SELECT coin_pub FROM rc)" -             " AND deposit_serial_id=(SELECT deposit_serial_id FROM rc)" -             ") dep" -             " JOIN rv" -             "  ON (rv.wire_target_h_payto=dep.wire_target_h_payto)" -             ); +             ",rc.merchant_pub" +             " FROM wire_targets wt" +             " JOIN rc" +             "   USING (wire_target_h_payto);");      break;    default:      GNUNET_break (0); diff --git a/src/exchangedb/pg_reserves_in_insert.c b/src/exchangedb/pg_reserves_in_insert.c index 0fdc4a16..314e89d8 100644 --- a/src/exchangedb/pg_reserves_in_insert.c +++ b/src/exchangedb/pg_reserves_in_insert.c @@ -27,6 +27,8 @@  #include "pg_start.h"  #include "pg_start_read_committed.h"  #include "pg_commit.h" +#include "pg_preflight.h" +#include "pg_rollback.h"  #include "pg_reserves_get.h"  #include "pg_reserves_update.h"  #include "pg_setup_wire_target.h" @@ -34,15 +36,13 @@  /** - * Generate event notification for the reserve - * change. + * Generate event notification for the reserve change.   * - * @param pg plugin state   * @param reserve_pub reserve to notfiy on + * @return string to pass to postgres for the notification   */ -static void -notify_on_reserve (struct PostgresClosure *pg, -                   const struct TALER_ReservePublicKeyP *reserve_pub) +static char * +compute_notify_on_reserve (const struct TALER_ReservePublicKeyP *reserve_pub)  {    struct TALER_ReserveEventP rep = {      .header.size = htons (sizeof (rep)), @@ -50,246 +50,868 @@ notify_on_reserve (struct PostgresClosure *pg,      .reserve_pub = *reserve_pub    }; -  GNUNET_log (GNUNET_ERROR_TYPE_INFO, -              "Notifying on reserve!\n"); -  TEH_PG_event_notify (pg, -                       &rep.header, -                       NULL, -                       0); +  return GNUNET_PG_get_event_notify_channel (&rep.header); +} + + +static enum GNUNET_DB_QueryStatus +insert1 (struct PostgresClosure *pg, +         const struct TALER_EXCHANGEDB_ReserveInInfo reserves[1], +         struct GNUNET_TIME_Timestamp expiry, +         struct GNUNET_TIME_Timestamp gc, +         struct TALER_PaytoHashP h_payto, +         char *const *notify_s, +         struct GNUNET_TIME_Timestamp reserve_expiration, +         bool *transaction_duplicate, +         bool *conflict, +         uint64_t *reserve_uuid, +         enum GNUNET_DB_QueryStatus results[1]) +{ +  enum GNUNET_DB_QueryStatus qs2; +  PREPARE (pg, +           "batch1_reserve_create", +           "SELECT " +           " out_reserve_found AS conflicted" +           ",transaction_duplicate" +           ",ruuid AS reserve_uuid" +           " FROM exchange_do_batch_reserves_in_insert" +           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"); + +  struct GNUNET_PQ_QueryParam params[] = { +    GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), +    GNUNET_PQ_query_param_timestamp (&expiry), +    GNUNET_PQ_query_param_timestamp (&gc), +    GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), +    TALER_PQ_query_param_amount (reserves[0].balance), +    GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[0].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), +    GNUNET_PQ_query_param_string (notify_s[0]), +    GNUNET_PQ_query_param_end +  }; + +  struct GNUNET_PQ_ResultSpec rs[] = { +    GNUNET_PQ_result_spec_bool ("conflicted", +                                &conflict[0]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate", +                                &transaction_duplicate[0]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid", +                                  &reserve_uuid[0]), +    GNUNET_PQ_result_spec_end +  }; + + +  TALER_payto_hash (reserves[0].sender_account_details, +                    &h_payto); + +  qs2 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, +                                                  "batch1_reserve_create", +                                                  params, +                                                  rs); + +  if (qs2 < 0) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "Failed to create reserves 1(%d)\n", +                qs2); +    results[0] = qs2; +    return qs2; +  } +  GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs2); +  if ((! conflict[0]) && transaction_duplicate[0]) +  { +    GNUNET_break (0); +    TEH_PG_rollback (pg); +    results[0] = GNUNET_DB_STATUS_HARD_ERROR; +    return GNUNET_DB_STATUS_HARD_ERROR; +  } +  results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +  return qs2; +} + + +static enum GNUNET_DB_QueryStatus +insert2 (struct PostgresClosure *pg, +         const struct TALER_EXCHANGEDB_ReserveInInfo reserves[2], +         struct GNUNET_TIME_Timestamp expiry, +         struct GNUNET_TIME_Timestamp gc, +         struct TALER_PaytoHashP h_payto, +         char *const*notify_s, +         struct GNUNET_TIME_Timestamp reserve_expiration, +         bool *transaction_duplicate, +         bool *conflict, +         uint64_t *reserve_uuid, +         enum GNUNET_DB_QueryStatus results[1]) +{ +  enum GNUNET_DB_QueryStatus qs1; +  PREPARE (pg, +           "batch2_reserve_create", +           "SELECT " +           "out_reserve_found AS conflicted" +           ",out_reserve_found2 AS conflicted2" +           ",transaction_duplicate" +           ",transaction_duplicate2" +           ",ruuid AS reserve_uuid" +           ",ruuid2 AS reserve_uuid2" +           " FROM exchange_do_batch2_reserves_insert" +           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22);"); + +  struct GNUNET_PQ_QueryParam params[] = { + +    GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), +    GNUNET_PQ_query_param_timestamp (&expiry), +    GNUNET_PQ_query_param_timestamp (&gc), +    GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), +    TALER_PQ_query_param_amount (reserves[0].balance), +    GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[0].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), +    GNUNET_PQ_query_param_string (notify_s[0]), +    GNUNET_PQ_query_param_string (notify_s[1]), + +    GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), +    TALER_PQ_query_param_amount (reserves[1].balance), +    GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[1].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), +    GNUNET_PQ_query_param_end +  }; +  struct GNUNET_PQ_ResultSpec rs[] = { +    GNUNET_PQ_result_spec_bool ("conflicted", +                                &conflict[0]), +    GNUNET_PQ_result_spec_bool ("conflicted2", +                                &conflict[1]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate", +                                &transaction_duplicate[0]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate2", +                                &transaction_duplicate[1]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid", +                                  &reserve_uuid[0]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", +                                  &reserve_uuid[1]), +    GNUNET_PQ_result_spec_end +  }; + +  TALER_payto_hash (reserves[0].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[1].sender_account_details, +                    &h_payto); + + +  qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, +                                                  "batch2_reserve_create", +                                                  params, +                                                  rs); +  if (qs1 < 0) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "Failed to create reserves 2(%d)\n", +                qs1); +    results[0] = qs1; +    return qs1; +  } + +  GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1); +  /*   results[i] = (transaction_duplicate) +    ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS +    : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ + +  if ( +    ((! conflict[0]) && (transaction_duplicate[0])) +    || ((! conflict[1]) && (transaction_duplicate[1])) +    ) +  { +    GNUNET_break (0); +    TEH_PG_rollback (pg);  // ROLLBACK +    results[0] = GNUNET_DB_STATUS_HARD_ERROR; +    return GNUNET_DB_STATUS_HARD_ERROR; +  } +  results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +  return qs1; +} + + +static enum GNUNET_DB_QueryStatus +insert4 (struct PostgresClosure *pg, +         const struct TALER_EXCHANGEDB_ReserveInInfo reserves[4], +         struct GNUNET_TIME_Timestamp expiry, +         struct GNUNET_TIME_Timestamp gc, +         struct TALER_PaytoHashP h_payto, +         char *const*notify_s, +         struct GNUNET_TIME_Timestamp reserve_expiration, +         bool *transaction_duplicate, +         bool *conflict, +         uint64_t *reserve_uuid, +         enum GNUNET_DB_QueryStatus results[1]) +{ +  enum GNUNET_DB_QueryStatus qs3; +  PREPARE (pg, +           "batch4_reserve_create", +           "SELECT " +           "out_reserve_found AS conflicted" +           ",out_reserve_found2 AS conflicted2" +           ",out_reserve_found3 AS conflicted3" +           ",out_reserve_found4 AS conflicted4" +           ",transaction_duplicate" +           ",transaction_duplicate2" +           ",transaction_duplicate3" +           ",transaction_duplicate4" +           ",ruuid AS reserve_uuid" +           ",ruuid2 AS reserve_uuid2" +           ",ruuid3 AS reserve_uuid3" +           ",ruuid4 AS reserve_uuid4" +           " FROM exchange_do_batch4_reserves_insert" +           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42);"); + +  struct GNUNET_PQ_QueryParam params[] = { +    GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), +    GNUNET_PQ_query_param_timestamp (&expiry), +    GNUNET_PQ_query_param_timestamp (&gc), +    GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), +    TALER_PQ_query_param_amount (reserves[0].balance), +    GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[0].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), +    GNUNET_PQ_query_param_string (notify_s[0]), +    GNUNET_PQ_query_param_string (notify_s[1]), +    GNUNET_PQ_query_param_string (notify_s[2]), +    GNUNET_PQ_query_param_string (notify_s[3]), + +    GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), +    TALER_PQ_query_param_amount (reserves[1].balance), +    GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[1].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), +    TALER_PQ_query_param_amount (reserves[2].balance), +    GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[2].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), +    TALER_PQ_query_param_amount (reserves[3].balance), +    GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[3].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_end +  }; + +  struct GNUNET_PQ_ResultSpec rs[] = { +    GNUNET_PQ_result_spec_bool ("conflicted", +                                &conflict[0]), +    GNUNET_PQ_result_spec_bool ("conflicted2", +                                &conflict[1]), +    GNUNET_PQ_result_spec_bool ("conflicted3", +                                &conflict[2]), +    GNUNET_PQ_result_spec_bool ("conflicted4", +                                &conflict[3]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate", +                                &transaction_duplicate[0]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate2", +                                &transaction_duplicate[1]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate3", +                                &transaction_duplicate[2]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate4", +                                &transaction_duplicate[3]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid", +                                  &reserve_uuid[0]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", +                                  &reserve_uuid[1]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", +                                  &reserve_uuid[2]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", +                                  &reserve_uuid[3]), +    GNUNET_PQ_result_spec_end +  }; + +  TALER_payto_hash (reserves[0].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[1].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[2].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[3].sender_account_details, +                    &h_payto); + +  qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, +                                                  "batch4_reserve_create", +                                                  params, +                                                  rs); +  if (qs3 < 0) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "Failed to create reserves4 (%d)\n", +                qs3); +    results[0] = qs3; +    return qs3; +  } + +  GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); + +  if ( +    ((! conflict[0]) && (transaction_duplicate[0])) +    || ((! conflict[1]) && (transaction_duplicate[1])) +    || ((! conflict[2]) && (transaction_duplicate[2])) +    || ((! conflict[3]) && (transaction_duplicate[3])) +    ) +  { +    GNUNET_break (0); +    TEH_PG_rollback (pg); +    results[0] = GNUNET_DB_STATUS_HARD_ERROR; +    return GNUNET_DB_STATUS_HARD_ERROR; +  } +  results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +  return qs3; +} + + +static enum GNUNET_DB_QueryStatus +insert8 (struct PostgresClosure *pg, +         const struct TALER_EXCHANGEDB_ReserveInInfo reserves[8], +         struct GNUNET_TIME_Timestamp expiry, +         struct GNUNET_TIME_Timestamp gc, +         struct TALER_PaytoHashP h_payto, +         char *const*notify_s, +         struct GNUNET_TIME_Timestamp reserve_expiration, +         bool *transaction_duplicate, +         bool *conflict, +         uint64_t *reserve_uuid, +         enum GNUNET_DB_QueryStatus results[1]) +{ +  enum GNUNET_DB_QueryStatus qs3; +  PREPARE (pg, +           "batch8_reserve_create", +           "SELECT " +           "out_reserve_found AS conflicted" +           ",out_reserve_found2 AS conflicted2" +           ",out_reserve_found3 AS conflicted3" +           ",out_reserve_found4 AS conflicted4" +           ",out_reserve_found5 AS conflicted5" +           ",out_reserve_found6 AS conflicted6" +           ",out_reserve_found7 AS conflicted7" +           ",out_reserve_found8 AS conflicted8" +           ",transaction_duplicate" +           ",transaction_duplicate2" +           ",transaction_duplicate3" +           ",transaction_duplicate4" +           ",transaction_duplicate5" +           ",transaction_duplicate6" +           ",transaction_duplicate7" +           ",transaction_duplicate8" +           ",ruuid AS reserve_uuid" +           ",ruuid2 AS reserve_uuid2" +           ",ruuid3 AS reserve_uuid3" +           ",ruuid4 AS reserve_uuid4" +           ",ruuid5 AS reserve_uuid5" +           ",ruuid6 AS reserve_uuid6" +           ",ruuid7 AS reserve_uuid7" +           ",ruuid8 AS reserve_uuid8" +           " FROM exchange_do_batch8_reserves_insert" +           " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39, $40, $41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$80,$81,$82);"); + +  struct GNUNET_PQ_QueryParam params[] = { +    GNUNET_PQ_query_param_auto_from_type (reserves[0].reserve_pub), +    GNUNET_PQ_query_param_timestamp (&expiry), +    GNUNET_PQ_query_param_timestamp (&gc), +    GNUNET_PQ_query_param_uint64 (&reserves[0].wire_reference), +    TALER_PQ_query_param_amount (reserves[0].balance), +    GNUNET_PQ_query_param_string (reserves[0].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[0].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[0].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), +    GNUNET_PQ_query_param_string (notify_s[0]), +    GNUNET_PQ_query_param_string (notify_s[1]), +    GNUNET_PQ_query_param_string (notify_s[2]), +    GNUNET_PQ_query_param_string (notify_s[3]), +    GNUNET_PQ_query_param_string (notify_s[4]), +    GNUNET_PQ_query_param_string (notify_s[5]), +    GNUNET_PQ_query_param_string (notify_s[6]), +    GNUNET_PQ_query_param_string (notify_s[7]), + +    GNUNET_PQ_query_param_auto_from_type (reserves[1].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[1].wire_reference), +    TALER_PQ_query_param_amount (reserves[1].balance), +    GNUNET_PQ_query_param_string (reserves[1].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[1].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[1].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[2].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[2].wire_reference), +    TALER_PQ_query_param_amount (reserves[2].balance), +    GNUNET_PQ_query_param_string (reserves[2].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[2].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[2].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[3].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[3].wire_reference), +    TALER_PQ_query_param_amount (reserves[3].balance), +    GNUNET_PQ_query_param_string (reserves[3].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[3].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[3].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[4].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[4].wire_reference), +    TALER_PQ_query_param_amount (reserves[4].balance), +    GNUNET_PQ_query_param_string (reserves[4].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[4].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[4].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[5].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[5].wire_reference), +    TALER_PQ_query_param_amount (reserves[5].balance), +    GNUNET_PQ_query_param_string (reserves[5].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[5].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[5].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[6].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[6].wire_reference), +    TALER_PQ_query_param_amount (reserves[6].balance), +    GNUNET_PQ_query_param_string (reserves[6].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[6].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[6].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_auto_from_type (reserves[7].reserve_pub), +    GNUNET_PQ_query_param_uint64 (&reserves[7].wire_reference), +    TALER_PQ_query_param_amount (reserves[7].balance), +    GNUNET_PQ_query_param_string (reserves[7].exchange_account_name), +    GNUNET_PQ_query_param_timestamp (&reserves[7].execution_time), +    GNUNET_PQ_query_param_auto_from_type (&h_payto), +    GNUNET_PQ_query_param_string (reserves[7].sender_account_details), +    GNUNET_PQ_query_param_timestamp (&reserve_expiration), + +    GNUNET_PQ_query_param_end +  }; + +  struct GNUNET_PQ_ResultSpec rs[] = { +    GNUNET_PQ_result_spec_bool ("conflicted", +                                &conflict[0]), +    GNUNET_PQ_result_spec_bool ("conflicted2", +                                &conflict[1]), +    GNUNET_PQ_result_spec_bool ("conflicted3", +                                &conflict[2]), +    GNUNET_PQ_result_spec_bool ("conflicted4", +                                &conflict[3]), +    GNUNET_PQ_result_spec_bool ("conflicted5", +                                &conflict[4]), +    GNUNET_PQ_result_spec_bool ("conflicted6", +                                &conflict[5]), +    GNUNET_PQ_result_spec_bool ("conflicted7", +                                &conflict[6]), +    GNUNET_PQ_result_spec_bool ("conflicted8", +                                &conflict[7]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate", +                                &transaction_duplicate[0]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate2", +                                &transaction_duplicate[1]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate3", +                                &transaction_duplicate[2]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate4", +                                &transaction_duplicate[3]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate5", +                                &transaction_duplicate[4]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate6", +                                &transaction_duplicate[5]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate7", +                                &transaction_duplicate[6]), +    GNUNET_PQ_result_spec_bool ("transaction_duplicate8", +                                &transaction_duplicate[7]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid", +                                  &reserve_uuid[0]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid2", +                                  &reserve_uuid[1]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid3", +                                  &reserve_uuid[2]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid4", +                                  &reserve_uuid[3]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid5", +                                  &reserve_uuid[4]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid6", +                                  &reserve_uuid[5]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid7", +                                  &reserve_uuid[6]), +    GNUNET_PQ_result_spec_uint64 ("reserve_uuid8", +                                  &reserve_uuid[7]), +    GNUNET_PQ_result_spec_end +  }; + +  TALER_payto_hash (reserves[0].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[1].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[2].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[3].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[4].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[5].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[6].sender_account_details, +                    &h_payto); +  TALER_payto_hash (reserves[7].sender_account_details, +                    &h_payto); + +  qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, +                                                  "batch8_reserve_create", +                                                  params, +                                                  rs); +  if (qs3 < 0) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "Failed to create reserves8 (%d)\n", +                qs3); +    results[0] = qs3; +    return qs3; +  } + +  GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs3); +  /*   results[i] = (transaction_duplicate) +     ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS +     : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;*/ + +  if ( +    ((! conflict[0]) && (transaction_duplicate[0])) +    || ((! conflict[1]) && (transaction_duplicate[1])) +    || ((! conflict[2]) && (transaction_duplicate[2])) +    || ((! conflict[3]) && (transaction_duplicate[3])) +    || ((! conflict[4]) && (transaction_duplicate[4])) +    || ((! conflict[5]) && (transaction_duplicate[5])) +    || ((! conflict[6]) && (transaction_duplicate[6])) +    || ((! conflict[7]) && (transaction_duplicate[7])) +    ) +  { +    GNUNET_break (0); +    TEH_PG_rollback (pg); +    results[0] = GNUNET_DB_STATUS_HARD_ERROR; +    return GNUNET_DB_STATUS_HARD_ERROR; +  } +  results[0] = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +  return qs3;  }  enum GNUNET_DB_QueryStatus  TEH_PG_reserves_in_insert (void *cls, -                           const struct TALER_ReservePublicKeyP *reserve_pub, -                           const struct TALER_Amount *balance, -                           struct GNUNET_TIME_Timestamp execution_time, -                           const char *sender_account_details, -                           const char *exchange_account_section, -                           uint64_t wire_ref) +                           const struct +                           TALER_EXCHANGEDB_ReserveInInfo *reserves, +                           unsigned int reserves_length, +                           unsigned int batch_size, +                           enum GNUNET_DB_QueryStatus *results)  {    struct PostgresClosure *pg = cls;    enum GNUNET_DB_QueryStatus qs1; -  struct TALER_EXCHANGEDB_Reserve reserve; +  enum GNUNET_DB_QueryStatus qs2; +  enum GNUNET_DB_QueryStatus qs4; +  enum GNUNET_DB_QueryStatus qs5;    struct GNUNET_TIME_Timestamp expiry;    struct GNUNET_TIME_Timestamp gc; -  uint64_t reserve_uuid; +  struct TALER_PaytoHashP h_payto; +  uint64_t reserve_uuid[reserves_length]; +  bool transaction_duplicate[reserves_length]; +  bool need_update = false; +  bool t_duplicate = false; +  struct GNUNET_TIME_Timestamp reserve_expiration +    = GNUNET_TIME_relative_to_timestamp (pg->idle_reserve_expiration_time); +  bool conflicts[reserves_length]; +  char *notify_s[reserves_length]; + +  if (GNUNET_OK != +      TEH_PG_preflight (pg)) +  { +    GNUNET_break (0); +    return GNUNET_DB_STATUS_HARD_ERROR; +  } -  reserve.pub = *reserve_pub;    expiry = GNUNET_TIME_absolute_to_timestamp ( -    GNUNET_TIME_absolute_add (execution_time.abs_time, +    GNUNET_TIME_absolute_add (reserves->execution_time.abs_time,                                pg->idle_reserve_expiration_time));    gc = GNUNET_TIME_absolute_to_timestamp (      GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),                                pg->legal_reserve_expiration_time));    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                "Creating reserve %s with expiration in %s\n", -              TALER_B2S (reserve_pub), +              TALER_B2S (&(reserves->reserve_pub)),                GNUNET_STRINGS_relative_time_to_string (                  pg->idle_reserve_expiration_time,                  GNUNET_NO)); + +  if (GNUNET_OK != +      TEH_PG_start_read_committed (pg, +                                   "READ_COMMITED")) +  { +    GNUNET_break (0); +    return GNUNET_DB_STATUS_HARD_ERROR; +  } +    /* Optimistically assume this is a new reserve, create balance for the first       time; we do this before adding the actual transaction to "reserves_in",       as for a new reserve it can't be a duplicate 'add' operation, and as       the 'add' operation needs the reserve entry as a foreign key. */ +  for (unsigned int i = 0; i<reserves_length; i++)    { -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (reserve_pub), -      TALER_PQ_query_param_amount (balance), -      GNUNET_PQ_query_param_timestamp (&expiry), -      GNUNET_PQ_query_param_timestamp (&gc), -      GNUNET_PQ_query_param_end -    }; -    struct GNUNET_PQ_ResultSpec rs[] = { -      GNUNET_PQ_result_spec_uint64 ("reserve_uuid", -                                    &reserve_uuid), -      GNUNET_PQ_result_spec_end -    }; - -    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -                "Reserve does not exist; creating a new one\n"); -    /* Note: query uses 'on conflict do nothing' */ -    PREPARE (pg, -             "reserve_create", -             "INSERT INTO reserves " -             "(reserve_pub" -             ",current_balance_val" -             ",current_balance_frac" -             ",expiration_date" -             ",gc_date" -             ") VALUES " -             "($1, $2, $3, $4, $5)" -             " ON CONFLICT DO NOTHING" -             " RETURNING reserve_uuid;"); -    qs1 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, -                                                    "reserve_create", -                                                    params, -                                                    rs); -    if (qs1 < 0) -      return qs1; +    const struct TALER_EXCHANGEDB_ReserveInInfo *reserve = &reserves[i]; + +    notify_s[i] = compute_notify_on_reserve (reserve->reserve_pub);    } -  /* Create new incoming transaction, "ON CONFLICT DO NOTHING" -     is again used to guard against duplicates. */ +  unsigned int i = 0; + +  while (i < reserves_length)    { -    enum GNUNET_DB_QueryStatus qs2; -    enum GNUNET_DB_QueryStatus qs3; -    struct TALER_PaytoHashP h_payto; - -    qs3 = TEH_PG_setup_wire_target (pg, -                                    sender_account_details, -                                    &h_payto); -    if (qs3 < 0) -      return qs3; -    /* We do not have the UUID, so insert by public key */ -    struct GNUNET_PQ_QueryParam params[] = { -      GNUNET_PQ_query_param_auto_from_type (&reserve.pub), -      GNUNET_PQ_query_param_uint64 (&wire_ref), -      TALER_PQ_query_param_amount (balance), -      GNUNET_PQ_query_param_string (exchange_account_section), -      GNUNET_PQ_query_param_auto_from_type (&h_payto), -      GNUNET_PQ_query_param_timestamp (&execution_time), -      GNUNET_PQ_query_param_end -    }; - -    PREPARE (pg, -             "reserves_in_add_transaction", -             "INSERT INTO reserves_in " -             "(reserve_pub" -             ",wire_reference" -             ",credit_val" -             ",credit_frac" -             ",exchange_account_section" -             ",wire_source_h_payto" -             ",execution_date" -             ") VALUES ($1, $2, $3, $4, $5, $6, $7)" -             " ON CONFLICT DO NOTHING;"); -    qs2 = GNUNET_PQ_eval_prepared_non_select (pg->conn, -                                              "reserves_in_add_transaction", -                                              params); -    /* qs2 could be 0 as statement used 'ON CONFLICT DO NOTHING' */ -    if (0 >= qs2) +    unsigned int bs = GNUNET_MIN (batch_size, +                                  reserves_length - i); +    if (bs >= 8)      { -      if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs2) && -           (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs1) ) +      qs1 = insert8 (pg, +                     &reserves[i], +                     expiry, +                     gc, +                     h_payto, +                     ¬ify_s[i], +                     reserve_expiration, +                     &transaction_duplicate[i], +                     &conflicts[i], +                     &reserve_uuid[i], +                     &results[i]); + +      if (qs1<0)        { -        /* Conflict for the transaction, but the reserve was -           just now created, that should be impossible. */ -        GNUNET_break (0); /* should be impossible: reserve was fresh, -                             but transaction already known */ -        return GNUNET_DB_STATUS_HARD_ERROR; +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Failed to create reserve batch_8 (%d)\n", +                    qs1); +        return qs1;        } -      /* Transaction was already known or error. We are finished. */ -      return qs2; +      need_update |= conflicts[i]; +      need_update |= conflicts[i + 1]; +      need_update |= conflicts[i + 2]; +      need_update |= conflicts[i + 3]; +      need_update |= conflicts[i + 4]; +      need_update |= conflicts[i + 5]; +      need_update |= conflicts[i + 6]; +      need_update |= conflicts[i + 7]; +      t_duplicate |= transaction_duplicate[i]; +      t_duplicate |= transaction_duplicate[i + 1]; +      t_duplicate |= transaction_duplicate[i + 2]; +      t_duplicate |= transaction_duplicate[i + 3]; +      t_duplicate |= transaction_duplicate[i + 4]; +      t_duplicate |= transaction_duplicate[i + 5]; +      t_duplicate |= transaction_duplicate[i + 6]; +      t_duplicate |= transaction_duplicate[i + 7]; +      i += 8; +      continue;      } -  } -  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs1) -  { -    /* New reserve, we are finished */ -    notify_on_reserve (pg, -                       reserve_pub); -    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -  } +    switch (bs) +    { +    case 7: +    case 6: +    case 5: +    case 4: +      qs4 = insert4 (pg, +                     &reserves[i], +                     expiry, +                     gc, +                     h_payto, +                     ¬ify_s[i], +                     reserve_expiration, +                     &transaction_duplicate[i], +                     &conflicts[i], +                     &reserve_uuid[i], +                     &results[i]); -  /* we were wrong with our optimistic assumption: -     reserve did already exist, need to do an update instead */ +      if (qs4<0) +      { +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Failed to create reserve batch_4 (%d)\n", +                    qs4); +        return qs4; +      } +      need_update |= conflicts[i]; +      need_update |= conflicts[i + 1]; +      need_update |= conflicts[i + 2]; +      need_update |= conflicts[i + 3]; +      t_duplicate |= transaction_duplicate[i]; +      t_duplicate |= transaction_duplicate[i + 1]; +      t_duplicate |= transaction_duplicate[i + 2]; +      t_duplicate |= transaction_duplicate[i + 3]; +      //  fprintf(stdout, "reserve_uuid : %ld %ld %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1], reserve_uuid[i+2], reserve_uuid[i+3]); +      i += 4; +      break; +    case 3: +    case 2: +      qs5 = insert2 (pg, +                     &reserves[i], +                     expiry, +                     gc, +                     h_payto, +                     ¬ify_s[i], +                     reserve_expiration, +                     &transaction_duplicate[i], +                     &conflicts[i], +                     &reserve_uuid[i], +                     &results[i]); +      if (qs5<0) +      { +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Failed to create reserve batch_2 (%d)\n", +                    qs5); +        return qs5; +      } +      need_update |= conflicts[i]; +      need_update |= conflicts[i + 1]; +      t_duplicate |= transaction_duplicate[i]; +      t_duplicate |= transaction_duplicate[i + 1]; +      results[i] = (t_duplicate) +      ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS +      : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +      //   fprintf(stdout, "reserve_uuid : %ld %ld\n", reserve_uuid[i], reserve_uuid[i+1]); +      i += 2; +      break; +    case 1: +      qs2 = insert1 (pg, +                     &reserves[i], +                     expiry, +                     gc, +                     h_payto, +                     ¬ify_s[i], +                     reserve_expiration, +                     &transaction_duplicate[i], +                     &conflicts[i], +                     &reserve_uuid[i], +                     &results[i]); +      if (qs2<0) +      { +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Failed to create reserve batch_1 (%d)\n)" +                    ,qs2); +        return qs2; +      } +      need_update |= conflicts[i]; +      t_duplicate |= transaction_duplicate[i]; +      //  fprintf(stdout, "reserve uuid : %ld c :%d t:%d\n", reserve_uuid[i], conflicts[i], transaction_duplicate[i]); +      i += 1; +      break; +    case 0: +      GNUNET_assert (0); +      break; +    } +  } /* end while */ +  // commit    { -    /* We need to move away from 'read committed' to serializable. -       Also, we know that it should be safe to commit at this point. -       (We are only run in a larger transaction for performance.) */      enum GNUNET_DB_QueryStatus cs;      cs = TEH_PG_commit (pg);      if (cs < 0) -      return cs; -    if (GNUNET_OK != -        TEH_PG_start (pg, -                      "reserve-update-serializable"))      { -      GNUNET_break (0); -      return GNUNET_DB_STATUS_HARD_ERROR; +      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                  "Failed to commit\n"); +      return cs;      }    } +  if (! need_update)    { -    enum GNUNET_DB_QueryStatus reserve_exists; - -    reserve_exists = TEH_PG_reserves_get (pg, -                                          &reserve); -    switch (reserve_exists) +    goto exit; +  } +  // begin serializable +  { +    if (GNUNET_OK != +        TEH_PG_start (pg, +                      "reserve-insert-continued"))      { -    case GNUNET_DB_STATUS_HARD_ERROR:        GNUNET_break (0); -      return reserve_exists; -    case GNUNET_DB_STATUS_SOFT_ERROR: -      return reserve_exists; -    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: -      /* First we got a conflict, but then we cannot select? Very strange. */ -      GNUNET_break (0); -      return GNUNET_DB_STATUS_SOFT_ERROR; -    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: -      /* continued below */ -      break; +      return GNUNET_DB_STATUS_HARD_ERROR;      }    } +  enum GNUNET_DB_QueryStatus qs3; +  PREPARE (pg, +           "reserves_update", +           "SELECT" +           " out_duplicate AS duplicate " +           "FROM exchange_do_batch_reserves_update" +           " ($1,$2,$3,$4,$5,$6,$7,$8);"); +  for (unsigned int i = 0; i<reserves_length; i++)    { -    struct TALER_EXCHANGEDB_Reserve updated_reserve; -    enum GNUNET_DB_QueryStatus qs3; - -    /* If the reserve already existed, we need to still update the -       balance; we do this after checking for duplication, as -       otherwise we might have to actually pay the cost to roll this -       back for duplicate transactions; like this, we should virtually -       never actually have to rollback anything. */ -    updated_reserve.pub = reserve.pub; -    if (0 > -        TALER_amount_add (&updated_reserve.balance, -                          &reserve.balance, -                          balance)) +    if (! conflicts[i]) +      continue;      { -      /* currency overflow or incompatible currency */ -      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Attempt to deposit incompatible amount into reserve\n"); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -    updated_reserve.expiry = GNUNET_TIME_timestamp_max (expiry, -                                                        reserve.expiry); -    updated_reserve.gc = GNUNET_TIME_timestamp_max (gc, -                                                    reserve.gc); -    qs3 = TEH_PG_reserves_update (pg, -                                  &updated_reserve); -    switch (qs3) -    { -    case GNUNET_DB_STATUS_HARD_ERROR: -      GNUNET_break (0); -      return qs3; -    case GNUNET_DB_STATUS_SOFT_ERROR: -      return qs3; -    case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: -      /* How can the UPDATE not work here? Very strange. */ -      GNUNET_break (0); -      return GNUNET_DB_STATUS_HARD_ERROR; -    case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: -      /* continued below */ -      break; +      bool duplicate; +      struct GNUNET_PQ_QueryParam params[] = { +        GNUNET_PQ_query_param_auto_from_type (reserves[i].reserve_pub), +        GNUNET_PQ_query_param_timestamp (&expiry), +        GNUNET_PQ_query_param_uint64 (&reserves[i].wire_reference), +        TALER_PQ_query_param_amount (reserves[i].balance), +        GNUNET_PQ_query_param_string (reserves[i].exchange_account_name), +        GNUNET_PQ_query_param_auto_from_type (&h_payto), +        GNUNET_PQ_query_param_string (notify_s[i]), +        GNUNET_PQ_query_param_end +      }; +      struct GNUNET_PQ_ResultSpec rs[] = { +        GNUNET_PQ_result_spec_bool ("duplicate", +                                    &duplicate), +        GNUNET_PQ_result_spec_end +      }; +      qs3 = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, +                                                      "reserves_update", +                                                      params, +                                                      rs); +      if (qs3<0) +      { +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Failed to update reserves (%d)\n", +                    qs3); +        results[i] = qs3; +        return qs3; +      } +      results[i] = duplicate +          ? GNUNET_DB_STATUS_SUCCESS_NO_RESULTS +          : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;      }    } -  notify_on_reserve (pg, -                     reserve_pub); -  /* Go back to original transaction mode */ +    {      enum GNUNET_DB_QueryStatus cs;      cs = TEH_PG_commit (pg);      if (cs < 0)        return cs; -    if (GNUNET_OK != -        TEH_PG_start_read_committed (pg, -                                     "reserve-insert-continued")) -    { -      GNUNET_break (0); -      return GNUNET_DB_STATUS_HARD_ERROR; -    }    } -  return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + +exit: +  for (unsigned int i = 0; i<reserves_length; i++) +    GNUNET_free (notify_s[i]); + +  return reserves_length;  } diff --git a/src/exchangedb/pg_reserves_in_insert.h b/src/exchangedb/pg_reserves_in_insert.h index 85401938..f92843e7 100644 --- a/src/exchangedb/pg_reserves_in_insert.h +++ b/src/exchangedb/pg_reserves_in_insert.h @@ -24,28 +24,26 @@  #include "taler_util.h"  #include "taler_json_lib.h"  #include "taler_exchangedb_plugin.h" + +  /**   * Insert an incoming transaction into reserves.  New reserves are also - * created through this function. Started within the scope of an ongoing - * transaction. + * created through this function. Runs its own transaction(s).   *   * @param cls the `struct PostgresClosure` with the plugin-specific state - * @param reserve_pub public key of the reserve - * @param balance the amount that has to be added to the reserve - * @param execution_time when was the amount added - * @param sender_account_details account information for the sender (payto://-URL) - * @param exchange_account_section name of the section in the configuration for the exchange's - *                       account into which the deposit was made - * @param wire_ref unique reference identifying the wire transfer + * @param reserves array of reserves to insert + * @param reserves_length length of the @a reserves array + * @param batch_size how many inserts to do in one go + * @param[out] results set to query status per reserve, must be of length @a reserves_length   * @return transaction status code   */  enum GNUNET_DB_QueryStatus -TEH_PG_reserves_in_insert (void *cls, -                             const struct TALER_ReservePublicKeyP *reserve_pub, -                             const struct TALER_Amount *balance, -                             struct GNUNET_TIME_Timestamp execution_time, -                             const char *sender_account_details, -                             const char *exchange_account_section, -                           uint64_t wire_ref); +TEH_PG_reserves_in_insert ( +  void *cls, +  const struct TALER_EXCHANGEDB_ReserveInInfo *reserves, +  unsigned int reserves_length, +  unsigned int batch_size, +  enum GNUNET_DB_QueryStatus *results); +  #endif diff --git a/src/exchangedb/pg_select_refunds_by_coin.c b/src/exchangedb/pg_select_refunds_by_coin.c index 255cac34..7325b359 100644 --- a/src/exchangedb/pg_select_refunds_by_coin.c +++ b/src/exchangedb/pg_select_refunds_by_coin.c @@ -129,7 +129,7 @@ TEH_PG_select_refunds_by_coin (    if (-2 == percent_refund)    { -    const char *mode = getenv ("NEW_LOGIC"); +    const char *mode = getenv ("TALER_POSTGRES_SELECT_REFUNDS_BY_COIN_LOGIC");      char dummy;      if ( (NULL==mode) || @@ -137,14 +137,13 @@ TEH_PG_select_refunds_by_coin (                         "%d%c",                         &percent_refund,                         &dummy)) ) -      { -        if (NULL != mode) -          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                      "Bad mode `%s' specified\n", -                      mode); -      } -      if (NULL==mode) -        percent_refund=0; +    { +      if (NULL != mode) +        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                    "Bad mode `%s' specified\n", +                    mode); +      percent_refund = 0; +    }    }    switch (percent_refund) diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index a6e93221..b201ef55 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -203,8 +203,6 @@  #include "pg_reserves_update.h"  #include "pg_setup_wire_target.h"  #include "pg_compute_shard.h" -#include "pg_batch_reserves_in_insert.h" -#include "pg_batch2_reserves_in_insert.h"  #include "pg_insert_kyc_attributes.h"  #include "pg_update_kyc_attributes.h"  #include "pg_select_similar_kyc_attributes.h" @@ -747,10 +745,6 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)      = &TEH_PG_select_purse_by_merge_pub;    plugin->set_purse_balance      = &TEH_PG_set_purse_balance; -  plugin->batch_reserves_in_insert -    = &TEH_PG_batch_reserves_in_insert; -  plugin->batch2_reserves_in_insert -    = &TEH_PG_batch2_reserves_in_insert;    plugin->insert_kyc_attributes      = &TEH_PG_insert_kyc_attributes;    plugin->update_kyc_attributes diff --git a/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c b/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c deleted file mode 100644 index 1a1c60f3..00000000 --- a/src/exchangedb/test_exchangedb_batch_reserves_in_insert.c +++ /dev/null @@ -1,196 +0,0 @@ -/* -  This file is part of TALER -  Copyright (C) 2014-2022 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 exchangedb/test_exchangedb_by_j.c - * @brief test cases for DB interaction functions - * @author Joseph Xu - */ -#include "platform.h" -#include "taler_exchangedb_lib.h" -#include "taler_json_lib.h" -#include "taler_exchangedb_plugin.h" - -/**o - * Global result from the testcase. - */ -static int result; - -/** - * Report line of error if @a cond is true, and jump to label "drop". - */ -#define FAILIF(cond)                            \ -  do {                                          \ -      if (! (cond)) {break;}                    \ -    GNUNET_break (0);                           \ -    goto drop;                                  \ -  } while (0) - - -/** - * Initializes @a ptr with random data. - */ -#define RND_BLK(ptr)                                                    \ -  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, sizeof (*ptr)) - -/** - * Initializes @a ptr with zeros. - */ -#define ZR_BLK(ptr) \ -  memset (ptr, 0, sizeof (*ptr)) - - -/** - * Currency we use.  Must match test-exchange-db-*.conf. - */ -#define CURRENCY "EUR" - -/** - * Database plugin under test. - */ -static struct TALER_EXCHANGEDB_Plugin *plugin; - - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure with config - */ -static void -run (void *cls) -{ -  struct GNUNET_CONFIGURATION_Handle *cfg = cls; -  const uint32_t num_partitions = 10; - -  if (NULL == -      (plugin = TALER_EXCHANGEDB_plugin_load (cfg))) -  { -    GNUNET_break (0); -    result = 77; -    return; -  } -  (void) plugin->drop_tables (plugin->cls); -  if (GNUNET_OK != -      plugin->create_tables (plugin->cls, -                             true, -                             num_partitions)) -  { -    GNUNET_break (0); -    result = 77; -    goto cleanup; -  } - -  for (unsigned int i = 0; i< 8; i++) -  { -    static unsigned int batches[] = {1, 1, 2, 3, 4, 16, 64, 256}; -    const char *sndr = "payto://x-taler-bank/localhost:8080/1"; -    struct TALER_Amount value; -    unsigned int batch_size = batches[i]; -    struct GNUNET_TIME_Absolute now; -    struct GNUNET_TIME_Timestamp ts; -    struct GNUNET_TIME_Relative duration; -    struct TALER_ReservePublicKeyP reserve_pubs[batch_size]; -    struct TALER_EXCHANGEDB_ReserveInInfo reserves[batch_size]; -    enum GNUNET_DB_QueryStatus results[batch_size]; -    GNUNET_assert (GNUNET_OK == -                   TALER_string_to_amount (CURRENCY ":1.000010", -                                           &value)); -    now = GNUNET_TIME_absolute_get (); -    ts = GNUNET_TIME_timestamp_get (); - - -    for (unsigned int k = 0; k<batch_size; k++) -      { -        RND_BLK (&reserve_pubs[k]); -        reserves[k].reserve_pub = &reserve_pubs[k]; -        reserves[k].balance = &value; -        reserves[k].execution_time = ts; -        reserves[k].sender_account_details = sndr; -        reserves[k].exchange_account_name = "name"; -        reserves[k].wire_reference = k; -      } -    FAILIF (batch_size != -            plugin->batch_reserves_in_insert (plugin->cls, -                                              reserves, -                                              batch_size, -                                              results)); - - -    duration = GNUNET_TIME_absolute_get_duration (now); -    fprintf (stdout, -             "for a batchsize equal to %d it took %s\n", -             batch_size, -             GNUNET_STRINGS_relative_time_to_string (duration, -                                                     GNUNET_NO) ); - -  } -  result = 0; -drop: -  GNUNET_break (GNUNET_OK == -                plugin->drop_tables (plugin->cls)); -cleanup: -  TALER_EXCHANGEDB_plugin_unload (plugin); -  plugin = NULL; -} - - -int -main (int argc, -      char *const argv[]) -{ -  const char *plugin_name; -  char *config_filename; -  char *testname; -  struct GNUNET_CONFIGURATION_Handle *cfg; -  (void) argc; -  result = -1; -   if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) -  { -    GNUNET_break (0); -    return -1; -    } - -  GNUNET_log_setup (argv[0], -                    "WARNING", -                    NULL); -   plugin_name++; -    (void) GNUNET_asprintf (&testname, -                          "test-exchange-db-%s", -                          plugin_name); -    (void) GNUNET_asprintf (&config_filename, -                          "%s.conf", -                          testname); -  fprintf (stdout, -           "Using config: %s\n", -           config_filename); -  cfg = GNUNET_CONFIGURATION_create (); -  if (GNUNET_OK != -      GNUNET_CONFIGURATION_parse (cfg, -                                  config_filename)) -  { -    GNUNET_break (0); -    GNUNET_free (config_filename); -    GNUNET_free (testname); -    return 2; -  } -  GNUNET_SCHEDULER_run (&run, -                        cfg); -  GNUNET_CONFIGURATION_destroy (cfg); -  GNUNET_free (config_filename); -  GNUNET_free (testname); -  return result; -} - -/* end of test_exchangedb_by_j.c */  | 
