test_exchangedb.c (92931B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file exchangedb/test_exchangedb.c 18 * @brief test cases for DB interaction functions 19 * @author Sree Harsha Totakura 20 * @author Christian Grothoff 21 * @author Marcello Stanisci 22 * @author Özgür Kesim 23 */ 24 #include "taler/platform.h" 25 #include "taler/taler_exchangedb_lib.h" 26 #include "taler/taler_json_lib.h" 27 #include "taler/taler_exchangedb_plugin.h" 28 29 /** 30 * Global result from the testcase. 31 */ 32 static int result; 33 34 /** 35 * Report line of error if @a cond is true, and jump to label "drop". 36 */ 37 #define FAILIF(cond) \ 38 do { \ 39 if (! (cond)) { break;} \ 40 GNUNET_break (0); \ 41 goto drop; \ 42 } while (0) 43 44 45 /** 46 * Initializes @a ptr with random data. 47 */ 48 #define RND_BLK(ptr) \ 49 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, ptr, \ 50 sizeof (*ptr)) 51 52 /** 53 * Initializes @a ptr with zeros. 54 */ 55 #define ZR_BLK(ptr) \ 56 memset (ptr, 0, sizeof (*ptr)) 57 58 59 /** 60 * Currency we use. Must match test-exchange-db-*.conf. 61 */ 62 #define CURRENCY "EUR" 63 64 /** 65 * Database plugin under test. 66 */ 67 static struct TALER_EXCHANGEDB_Plugin *plugin; 68 69 70 /** 71 * Callback that should never be called. 72 */ 73 static void 74 dead_prepare_cb (void *cls, 75 uint64_t rowid, 76 const char *wire_method, 77 const char *buf, 78 size_t buf_size) 79 { 80 (void) cls; 81 (void) rowid; 82 (void) wire_method; 83 (void) buf; 84 (void) buf_size; 85 GNUNET_assert (0); 86 } 87 88 89 /** 90 * Callback that is called with wire prepare data 91 * and then marks it as finished. 92 */ 93 static void 94 mark_prepare_cb (void *cls, 95 uint64_t rowid, 96 const char *wire_method, 97 const char *buf, 98 size_t buf_size) 99 { 100 (void) cls; 101 GNUNET_assert (11 == buf_size); 102 GNUNET_assert (0 == strcasecmp (wire_method, 103 "testcase")); 104 GNUNET_assert (0 == memcmp (buf, 105 "hello world", 106 buf_size)); 107 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 108 plugin->wire_prepare_data_mark_finished (plugin->cls, 109 rowid)); 110 } 111 112 113 /** 114 * Simple check that config retrieval and setting for extensions work 115 */ 116 static enum GNUNET_GenericReturnValue 117 test_extension_manifest (void) 118 { 119 char *manifest; 120 121 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 122 plugin->get_extension_manifest (plugin->cls, 123 "fnord", 124 &manifest)); 125 126 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 127 plugin->set_extension_manifest (plugin->cls, 128 "fnord", 129 "bar")); 130 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 131 plugin->get_extension_manifest (plugin->cls, 132 "fnord", 133 &manifest)); 134 135 FAILIF (0 != strcmp ("bar", manifest)); 136 GNUNET_free (manifest); 137 138 /* let's do this again! */ 139 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 140 plugin->set_extension_manifest (plugin->cls, 141 "fnord", 142 "buzz")); 143 144 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 145 plugin->get_extension_manifest (plugin->cls, 146 "fnord", 147 &manifest)); 148 149 FAILIF (0 != strcmp ("buzz", manifest)); 150 GNUNET_free (manifest); 151 152 /* let's do this again, with NULL */ 153 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 154 plugin->set_extension_manifest (plugin->cls, 155 "fnord", 156 NULL)); 157 158 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 159 plugin->get_extension_manifest (plugin->cls, 160 "fnord", 161 &manifest)); 162 163 FAILIF (NULL != manifest); 164 165 return GNUNET_OK; 166 drop: 167 return GNUNET_SYSERR; 168 } 169 170 171 /** 172 * Test API relating to persisting the wire plugins preparation data. 173 * 174 * @return #GNUNET_OK on success 175 */ 176 static enum GNUNET_GenericReturnValue 177 test_wire_prepare (void) 178 { 179 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 180 plugin->wire_prepare_data_get (plugin->cls, 181 0, 182 1, 183 &dead_prepare_cb, 184 NULL)); 185 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 186 plugin->wire_prepare_data_insert (plugin->cls, 187 "testcase", 188 "hello world", 189 11)); 190 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 191 plugin->wire_prepare_data_get (plugin->cls, 192 0, 193 1, 194 &mark_prepare_cb, 195 NULL)); 196 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 197 plugin->wire_prepare_data_get (plugin->cls, 198 0, 199 1, 200 &dead_prepare_cb, 201 NULL)); 202 return GNUNET_OK; 203 drop: 204 return GNUNET_SYSERR; 205 } 206 207 208 /** 209 * Checks if the given reserve has the given amount of balance and expiry 210 * 211 * @param pub the public key of the reserve 212 * @param value balance value 213 * @param fraction balance fraction 214 * @param currency currency of the reserve 215 * @return #GNUNET_OK if the given reserve has the same balance and expiration 216 * as the given parameters; #GNUNET_SYSERR if not 217 */ 218 static enum GNUNET_GenericReturnValue 219 check_reserve (const struct TALER_ReservePublicKeyP *pub, 220 uint64_t value, 221 uint32_t fraction, 222 const char *currency) 223 { 224 struct TALER_EXCHANGEDB_Reserve reserve; 225 226 reserve.pub = *pub; 227 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 228 plugin->reserves_get (plugin->cls, 229 &reserve)); 230 FAILIF (value != reserve.balance.value); 231 FAILIF (fraction != reserve.balance.fraction); 232 FAILIF (0 != strcmp (currency, 233 reserve.balance.currency)); 234 return GNUNET_OK; 235 drop: 236 return GNUNET_SYSERR; 237 } 238 239 240 struct DenomKeyPair 241 { 242 struct TALER_DenominationPrivateKey priv; 243 struct TALER_DenominationPublicKey pub; 244 }; 245 246 247 /** 248 * Destroy a denomination key pair. The key is not necessarily removed from the DB. 249 * 250 * @param dkp the key pair to destroy 251 */ 252 static void 253 destroy_denom_key_pair (struct DenomKeyPair *dkp) 254 { 255 TALER_denom_pub_free (&dkp->pub); 256 TALER_denom_priv_free (&dkp->priv); 257 GNUNET_free (dkp); 258 } 259 260 261 /** 262 * Create a denomination key pair by registering the denomination in the DB. 263 * 264 * @param size the size of the denomination key 265 * @param now time to use for key generation, legal expiration will be 3h later. 266 * @param fees fees to use 267 * @return the denominaiton key pair; NULL upon error 268 */ 269 static struct DenomKeyPair * 270 create_denom_key_pair (unsigned int size, 271 struct GNUNET_TIME_Timestamp now, 272 const struct TALER_Amount *value, 273 const struct TALER_DenomFeeSet *fees) 274 { 275 struct DenomKeyPair *dkp; 276 struct TALER_EXCHANGEDB_DenominationKey dki; 277 struct TALER_EXCHANGEDB_DenominationKeyInformation issue2; 278 279 dkp = GNUNET_new (struct DenomKeyPair); 280 GNUNET_assert (GNUNET_OK == 281 TALER_denom_priv_create (&dkp->priv, 282 &dkp->pub, 283 GNUNET_CRYPTO_BSA_RSA, 284 size)); 285 /* Using memset() as fields like master key and signature 286 are not properly initialized for this test. */ 287 memset (&dki, 288 0, 289 sizeof (struct TALER_EXCHANGEDB_DenominationKey)); 290 dki.denom_pub = dkp->pub; 291 dki.issue.start = now; 292 dki.issue.expire_withdraw 293 = GNUNET_TIME_absolute_to_timestamp ( 294 GNUNET_TIME_absolute_add ( 295 now.abs_time, 296 GNUNET_TIME_UNIT_HOURS)); 297 dki.issue.expire_deposit 298 = GNUNET_TIME_absolute_to_timestamp ( 299 GNUNET_TIME_absolute_add ( 300 now.abs_time, 301 GNUNET_TIME_relative_multiply ( 302 GNUNET_TIME_UNIT_HOURS, 2))); 303 dki.issue.expire_legal 304 = GNUNET_TIME_absolute_to_timestamp ( 305 GNUNET_TIME_absolute_add ( 306 now.abs_time, 307 GNUNET_TIME_relative_multiply ( 308 GNUNET_TIME_UNIT_HOURS, 3))); 309 dki.issue.value = *value; 310 dki.issue.fees = *fees; 311 TALER_denom_pub_hash (&dkp->pub, 312 &dki.issue.denom_hash); 313 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 314 plugin->insert_denomination_info (plugin->cls, 315 &dki.denom_pub, 316 &dki.issue)) 317 { 318 GNUNET_break (0); 319 destroy_denom_key_pair (dkp); 320 return NULL; 321 } 322 memset (&issue2, 0, sizeof (issue2)); 323 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 324 plugin->get_denomination_info (plugin->cls, 325 &dki.issue.denom_hash, 326 NULL, 327 &issue2)) 328 { 329 GNUNET_break (0); 330 destroy_denom_key_pair (dkp); 331 return NULL; 332 } 333 if (0 != GNUNET_memcmp (&dki.issue, 334 &issue2)) 335 { 336 GNUNET_break (0); 337 destroy_denom_key_pair (dkp); 338 return NULL; 339 } 340 return dkp; 341 } 342 343 344 static struct TALER_Amount global_amount; 345 static struct TALER_Amount global_value; 346 static struct TALER_DenomFeeSet global_fees; 347 static struct TALER_Amount fee_closing; 348 349 350 /** 351 * Number of newly minted coins to use in the test. 352 */ 353 #define MELT_NEW_COINS 5 354 355 /** 356 * Which index was 'randomly' chosen for the reveal for the test? 357 */ 358 #define MELT_NOREVEAL_INDEX 1 359 360 /** 361 * How big do we make the RSA keys? 362 */ 363 #define RSA_KEY_SIZE 1024 364 365 static struct TALER_EXCHANGEDB_RefreshRevealedCoin *revealed_coins; 366 367 static struct TALER_TransferPrivateKeyP tprivs[TALER_CNC_KAPPA]; 368 369 static struct TALER_TransferPublicKeyP tpub; 370 371 372 /** 373 * Function called with information about a refresh order. This 374 * one should not be called in a successful test. 375 * 376 * @param cls closure 377 * @param rowid unique serial ID for the row in our database 378 * @param num_freshcoins size of the @a rrcs array 379 * @param rrcs array of @a num_freshcoins information about coins to be created 380 */ 381 static void 382 never_called_cb (void *cls, 383 uint32_t num_freshcoins, 384 const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs) 385 { 386 (void) cls; 387 (void) num_freshcoins; 388 (void) rrcs; 389 GNUNET_assert (0); /* should never be called! */ 390 } 391 392 393 /** 394 * Function called with information about a refresh order. 395 * Checks that the response matches what we expect to see. 396 * 397 * @param cls closure 398 * @param rowid unique serial ID for the row in our database 399 * @param num_freshcoins size of the @a rrcs array 400 * @param rrcs array of @a num_freshcoins information about coins to be created 401 */ 402 static void 403 check_refresh_reveal_cb ( 404 void *cls, 405 uint32_t num_freshcoins, 406 const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs) 407 { 408 (void) cls; 409 /* compare the refresh commit coin arrays */ 410 for (unsigned int cnt = 0; cnt < num_freshcoins; cnt++) 411 { 412 const struct TALER_EXCHANGEDB_RefreshRevealedCoin *acoin = 413 &revealed_coins[cnt]; 414 const struct TALER_EXCHANGEDB_RefreshRevealedCoin *bcoin = &rrcs[cnt]; 415 416 GNUNET_assert (0 == 417 TALER_blinded_planchet_cmp (&acoin->blinded_planchet, 418 &bcoin->blinded_planchet)); 419 GNUNET_assert (0 == 420 GNUNET_memcmp (&acoin->h_denom_pub, 421 &bcoin->h_denom_pub)); 422 } 423 } 424 425 426 /** 427 * Counter used in auditor-related db functions. Used to count 428 * expected rows. 429 */ 430 static unsigned int auditor_row_cnt; 431 432 433 /** 434 * Function called with details about coins that were melted, 435 * with the goal of auditing the refresh's execution. 436 * 437 * 438 * @param cls closure 439 * @param rowid unique serial ID for the refresh session in our DB 440 * @param denom_pub denomination of the @a coin_pub 441 * @param h_age_commitment hash of age commitment that went into the minting, may be NULL 442 * @param coin_pub public key of the coin 443 * @param coin_sig signature from the coin 444 * @param amount_with_fee amount that was deposited including fee 445 * @param num_freshcoins how many coins were issued 446 * @param noreveal_index which index was picked by the exchange in cut-and-choose 447 * @param rc what is the session hash 448 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 449 */ 450 static enum GNUNET_GenericReturnValue 451 audit_refresh_session_cb ( 452 void *cls, 453 uint64_t rowid, 454 const struct TALER_DenominationPublicKey *denom_pub, 455 const struct TALER_AgeCommitmentHashP *h_age_commitment, 456 const struct TALER_CoinSpendPublicKeyP *coin_pub, 457 const struct TALER_CoinSpendSignatureP *coin_sig, 458 const struct TALER_Amount *amount_with_fee, 459 uint32_t noreveal_index, 460 const struct TALER_RefreshCommitmentP *rc) 461 { 462 (void) cls; 463 (void) rowid; 464 (void) denom_pub; 465 (void) coin_pub; 466 (void) coin_sig; 467 (void) amount_with_fee; 468 (void) noreveal_index; 469 (void) rc; 470 (void) h_age_commitment; 471 auditor_row_cnt++; 472 return GNUNET_OK; 473 } 474 475 476 /** 477 * Denomination keys used for fresh coins in melt test. 478 */ 479 static struct DenomKeyPair **new_dkp; 480 481 482 /** 483 * Function called with the session hashes and transfer secret 484 * information for a given coin. 485 * 486 * @param cls closure 487 * @param transfer_pub public transfer key for the session 488 * @param ldl link data for @a transfer_pub 489 */ 490 static void 491 handle_link_data_cb (void *cls, 492 const struct TALER_TransferPublicKeyP *transfer_pub, 493 const struct TALER_EXCHANGEDB_LinkList *ldl) 494 { 495 (void) cls; 496 (void) transfer_pub; 497 for (const struct TALER_EXCHANGEDB_LinkList *ldlp = ldl; 498 NULL != ldlp; 499 ldlp = ldlp->next) 500 { 501 bool found; 502 503 found = false; 504 for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) 505 { 506 if ( (0 == 507 TALER_denom_pub_cmp (&ldlp->denom_pub, 508 &new_dkp[cnt]->pub)) && 509 (0 == 510 TALER_blinded_denom_sig_cmp (&ldlp->ev_sig, 511 &revealed_coins[cnt].coin_sig)) ) 512 { 513 found = true; 514 break; 515 } 516 } 517 GNUNET_assert (GNUNET_NO != found); 518 } 519 } 520 521 522 /** 523 * Callback that should never be called. 524 */ 525 static void 526 cb_wt_never (void *cls, 527 uint64_t serial_id, 528 const struct TALER_MerchantPublicKeyP *merchant_pub, 529 const struct TALER_FullPayto account_payto_uri, 530 const struct TALER_FullPaytoHashP *h_payto, 531 struct GNUNET_TIME_Timestamp exec_time, 532 const struct TALER_PrivateContractHashP *h_contract_terms, 533 const struct TALER_DenominationPublicKey *denom_pub, 534 const struct TALER_CoinSpendPublicKeyP *coin_pub, 535 const struct TALER_Amount *coin_value, 536 const struct TALER_Amount *coin_fee) 537 { 538 (void) cls; 539 (void) serial_id; 540 (void) merchant_pub; 541 (void) account_payto_uri; 542 (void) h_payto; 543 (void) exec_time; 544 (void) h_contract_terms; 545 (void) denom_pub; 546 (void) coin_pub; 547 (void) coin_value; 548 (void) coin_fee; 549 GNUNET_assert (0); /* this statement should be unreachable */ 550 } 551 552 553 static struct TALER_MerchantPublicKeyP merchant_pub_wt; 554 static struct TALER_MerchantWireHashP h_wire_wt; 555 static struct TALER_PrivateContractHashP h_contract_terms_wt; 556 static struct TALER_CoinSpendPublicKeyP coin_pub_wt; 557 static struct TALER_Amount coin_value_wt; 558 static struct TALER_Amount coin_fee_wt; 559 static struct TALER_Amount transfer_value_wt; 560 static struct GNUNET_TIME_Timestamp wire_out_date; 561 static struct TALER_WireTransferIdentifierRawP wire_out_wtid; 562 563 564 /** 565 * Callback that should be called with the WT data. 566 */ 567 static void 568 cb_wt_check (void *cls, 569 uint64_t rowid, 570 const struct TALER_MerchantPublicKeyP *merchant_pub, 571 const struct TALER_FullPayto account_payto_uri, 572 const struct TALER_FullPaytoHashP *h_payto, 573 struct GNUNET_TIME_Timestamp exec_time, 574 const struct TALER_PrivateContractHashP *h_contract_terms, 575 const struct TALER_DenominationPublicKey *denom_pub, 576 const struct TALER_CoinSpendPublicKeyP *coin_pub, 577 const struct TALER_Amount *coin_value, 578 const struct TALER_Amount *coin_fee) 579 { 580 (void) rowid; 581 (void) denom_pub; 582 (void) h_payto; 583 GNUNET_assert (cls == &cb_wt_never); 584 GNUNET_assert (0 == GNUNET_memcmp (merchant_pub, 585 &merchant_pub_wt)); 586 GNUNET_assert (0 == strcmp (account_payto_uri.full_payto, 587 "payto://iban/DE67830654080004822650?receiver-name=Test")); 588 GNUNET_assert (GNUNET_TIME_timestamp_cmp (exec_time, 589 ==, 590 wire_out_date)); 591 GNUNET_assert (0 == GNUNET_memcmp (h_contract_terms, 592 &h_contract_terms_wt)); 593 GNUNET_assert (0 == GNUNET_memcmp (coin_pub, 594 &coin_pub_wt)); 595 GNUNET_assert (0 == TALER_amount_cmp (coin_value, 596 &coin_value_wt)); 597 GNUNET_assert (0 == TALER_amount_cmp (coin_fee, 598 &coin_fee_wt)); 599 } 600 601 602 /** 603 * Here we store the hash of the payto URI. 604 */ 605 static struct TALER_FullPaytoHashP global_wire_target_h_payto; 606 607 608 /** 609 * Callback for #select_coin_deposits_above_serial_id () 610 * 611 * @param cls closure 612 * @param rowid unique serial ID for the deposit in our DB 613 * @param exchange_timestamp when did the deposit happen 614 * @param deposit deposit details 615 * @param denom_pub denomination of the @a coin_pub 616 * @param done flag set if the deposit was already executed (or not) 617 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 618 */ 619 static enum GNUNET_GenericReturnValue 620 audit_deposit_cb (void *cls, 621 uint64_t rowid, 622 struct GNUNET_TIME_Timestamp exchange_timestamp, 623 const struct TALER_EXCHANGEDB_Deposit *deposit, 624 const struct TALER_DenominationPublicKey *denom_pub, 625 bool done) 626 { 627 (void) cls; 628 (void) rowid; 629 (void) exchange_timestamp; 630 (void) deposit; 631 (void) denom_pub; 632 (void) done; 633 auditor_row_cnt++; 634 return GNUNET_OK; 635 } 636 637 638 /** 639 * Function called with details about coins that were refunding, 640 * with the goal of auditing the refund's execution. 641 * 642 * @param cls closure 643 * @param rowid unique serial ID for the refund in our DB 644 * @param denom_pub denomination of the @a coin_pub 645 * @param coin_pub public key of the coin 646 * @param merchant_pub public key of the merchant 647 * @param merchant_sig signature of the merchant 648 * @param h_contract_terms hash of the proposal data in 649 * the contract between merchant and customer 650 * @param rtransaction_id refund transaction ID chosen by the merchant 651 * @param full_refund the deposit 652 * @param amount_with_fee amount that was deposited including fee 653 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 654 */ 655 static enum GNUNET_GenericReturnValue 656 audit_refund_cb (void *cls, 657 uint64_t rowid, 658 const struct TALER_DenominationPublicKey *denom_pub, 659 const struct TALER_CoinSpendPublicKeyP *coin_pub, 660 const struct TALER_MerchantPublicKeyP *merchant_pub, 661 const struct TALER_MerchantSignatureP *merchant_sig, 662 const struct TALER_PrivateContractHashP *h_contract_terms, 663 uint64_t rtransaction_id, 664 bool full_refund, 665 const struct TALER_Amount *amount_with_fee) 666 { 667 (void) cls; 668 (void) rowid; 669 (void) denom_pub; 670 (void) coin_pub; 671 (void) merchant_pub; 672 (void) merchant_sig; 673 (void) h_contract_terms; 674 (void) rtransaction_id; 675 (void) amount_with_fee; 676 (void) full_refund; 677 auditor_row_cnt++; 678 return GNUNET_OK; 679 } 680 681 682 /** 683 * Function called with details about incoming wire transfers. 684 * 685 * @param cls closure 686 * @param rowid unique serial ID for the refresh session in our DB 687 * @param reserve_pub public key of the reserve (also the WTID) 688 * @param credit amount that was received 689 * @param sender_account_details information about the sender's bank account 690 * @param wire_reference unique reference identifying the wire transfer 691 * @param execution_date when did we receive the funds 692 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 693 */ 694 static enum GNUNET_GenericReturnValue 695 audit_reserve_in_cb (void *cls, 696 uint64_t rowid, 697 const struct TALER_ReservePublicKeyP *reserve_pub, 698 const struct TALER_Amount *credit, 699 const struct TALER_FullPayto sender_account_details, 700 uint64_t wire_reference, 701 struct GNUNET_TIME_Timestamp execution_date) 702 { 703 (void) cls; 704 (void) rowid; 705 (void) reserve_pub; 706 (void) credit; 707 (void) sender_account_details; 708 (void) wire_reference; 709 (void) execution_date; 710 auditor_row_cnt++; 711 return GNUNET_OK; 712 } 713 714 715 /** 716 * Function called with details about withdraw operations. 717 * 718 * @param cls closure 719 * @param rowid unique serial ID for the refresh session in our DB 720 * @param num_evs number of elements in @e h_blind_evs 721 * @param h_blind_evs array @e num_evs of blinded hashes of the coin's public keys 722 * @param denom_serials array @e num_evs of serial ids of denominations 723 * @param h_planchets running hash over all hashes of blinded planchets in the original withdraw request 724 * @param blinding_seed seed provided during withdraw, for CS denominations; might be NULL 725 * @param age_proof_required true if the withdraw request required an age proof. 726 * @param max_age if @e age_proof_required is true, the maximum age that was set on the coins. 727 * @param noreveal_index if @e age_proof_required is true, the index that was returned by the exchange for the reveal phase. 728 * @param reserve_pub public key of the reserve 729 * @param reserve_sig signature over the withdraw operation 730 * @param execution_date when did the wallet withdraw the coin 731 * @param amount_with_fee amount that was withdrawn 732 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 733 */ 734 static enum GNUNET_GenericReturnValue 735 audit_reserve_out_cb (void *cls, 736 uint64_t rowid, 737 size_t num_evs, 738 const struct TALER_BlindedCoinHashP *h_blind_evs, 739 const uint64_t *denom_serials, 740 const struct TALER_HashBlindedPlanchetsP *h_planchets, 741 const struct TALER_BlindingMasterSeedP *blinding_seed, 742 bool age_proof_required, 743 uint8_t max_age, 744 uint8_t noreveal_index, 745 const struct TALER_ReservePublicKeyP *reserve_pub, 746 const struct TALER_ReserveSignatureP *reserve_sig, 747 struct GNUNET_TIME_Timestamp execution_date, 748 const struct TALER_Amount *amount_with_fee) 749 { 750 (void) cls; 751 (void) rowid; 752 (void) h_blind_evs; 753 (void) h_planchets; 754 (void) blinding_seed; 755 (void) denom_serials; 756 (void) reserve_pub; 757 (void) reserve_sig; 758 (void) execution_date; 759 (void) amount_with_fee; 760 auditor_row_cnt++; 761 return GNUNET_OK; 762 } 763 764 765 /** 766 * Test garbage collection. 767 * 768 * @return #GNUNET_OK on success 769 */ 770 static enum GNUNET_GenericReturnValue 771 test_gc (void) 772 { 773 struct DenomKeyPair *dkp; 774 struct GNUNET_TIME_Timestamp now; 775 struct GNUNET_TIME_Timestamp past; 776 struct TALER_EXCHANGEDB_DenominationKeyInformation issue2; 777 struct TALER_DenominationHashP denom_hash; 778 779 now = GNUNET_TIME_timestamp_get (); 780 past = GNUNET_TIME_absolute_to_timestamp ( 781 GNUNET_TIME_absolute_subtract (now.abs_time, 782 GNUNET_TIME_relative_multiply ( 783 GNUNET_TIME_UNIT_HOURS, 784 4))); 785 dkp = create_denom_key_pair (RSA_KEY_SIZE, 786 past, 787 &global_value, 788 &global_fees); 789 GNUNET_assert (NULL != dkp); 790 if (GNUNET_OK != 791 plugin->gc (plugin->cls)) 792 { 793 GNUNET_break (0); 794 destroy_denom_key_pair (dkp); 795 return GNUNET_SYSERR; 796 } 797 TALER_denom_pub_hash (&dkp->pub, 798 &denom_hash); 799 800 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 801 plugin->get_denomination_info (plugin->cls, 802 &denom_hash, 803 NULL, 804 &issue2)) 805 { 806 GNUNET_break (0); 807 destroy_denom_key_pair (dkp); 808 return GNUNET_SYSERR; 809 } 810 destroy_denom_key_pair (dkp); 811 return GNUNET_OK; 812 } 813 814 815 /** 816 * Test wire fee storage. 817 * 818 * @return #GNUNET_OK on success 819 */ 820 static enum GNUNET_GenericReturnValue 821 test_wire_fees (void) 822 { 823 struct GNUNET_TIME_Timestamp start_date; 824 struct GNUNET_TIME_Timestamp end_date; 825 struct TALER_WireFeeSet fees; 826 struct TALER_MasterSignatureP master_sig; 827 struct GNUNET_TIME_Timestamp sd; 828 struct GNUNET_TIME_Timestamp ed; 829 struct TALER_WireFeeSet fees2; 830 struct TALER_MasterSignatureP ms; 831 uint64_t rowid; 832 833 start_date = GNUNET_TIME_timestamp_get (); 834 end_date = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MINUTES); 835 GNUNET_assert (GNUNET_OK == 836 TALER_string_to_amount (CURRENCY ":1.424242", 837 &fees.wire)); 838 GNUNET_assert (GNUNET_OK == 839 TALER_string_to_amount (CURRENCY ":2.424242", 840 &fees.closing)); 841 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 842 &master_sig, 843 sizeof (master_sig)); 844 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 845 plugin->insert_wire_fee (plugin->cls, 846 "wire-method", 847 start_date, 848 end_date, 849 &fees, 850 &master_sig)) 851 { 852 GNUNET_break (0); 853 return GNUNET_SYSERR; 854 } 855 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 856 plugin->insert_wire_fee (plugin->cls, 857 "wire-method", 858 start_date, 859 end_date, 860 &fees, 861 &master_sig)) 862 { 863 GNUNET_break (0); 864 return GNUNET_SYSERR; 865 } 866 /* This must fail as 'end_date' is NOT in the 867 half-open interval [start_date,end_date) */ 868 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 869 plugin->get_wire_fee (plugin->cls, 870 "wire-method", 871 end_date, 872 &rowid, 873 &sd, 874 &ed, 875 &fees2, 876 &ms)) 877 { 878 GNUNET_break (0); 879 return GNUNET_SYSERR; 880 } 881 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 882 plugin->get_wire_fee (plugin->cls, 883 "wire-method", 884 start_date, 885 &rowid, 886 &sd, 887 &ed, 888 &fees2, 889 &ms)) 890 { 891 GNUNET_break (0); 892 return GNUNET_SYSERR; 893 } 894 if ( (GNUNET_TIME_timestamp_cmp (sd, 895 !=, 896 start_date)) || 897 (GNUNET_TIME_timestamp_cmp (ed, 898 !=, 899 end_date)) || 900 (0 != TALER_wire_fee_set_cmp (&fees, 901 &fees2)) || 902 (0 != GNUNET_memcmp (&ms, 903 &master_sig)) ) 904 { 905 GNUNET_break (0); 906 return GNUNET_SYSERR; 907 } 908 return GNUNET_OK; 909 } 910 911 912 static struct TALER_Amount wire_out_amount; 913 914 915 /** 916 * Callback with data about an executed wire transfer. 917 * 918 * @param cls closure 919 * @param rowid identifier of the respective row in the database 920 * @param date timestamp of the wire transfer (roughly) 921 * @param wtid wire transfer subject 922 * @param wire wire transfer details of the receiver 923 * @param amount amount that was wired 924 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration 925 */ 926 static enum GNUNET_GenericReturnValue 927 audit_wire_cb (void *cls, 928 uint64_t rowid, 929 struct GNUNET_TIME_Timestamp date, 930 const struct TALER_WireTransferIdentifierRawP *wtid, 931 const struct TALER_FullPayto payto_uri, 932 const struct TALER_Amount *amount) 933 { 934 (void) cls; 935 (void) rowid; 936 (void) payto_uri; 937 auditor_row_cnt++; 938 GNUNET_assert (0 == 939 TALER_amount_cmp (amount, 940 &wire_out_amount)); 941 GNUNET_assert (0 == 942 GNUNET_memcmp (wtid, 943 &wire_out_wtid)); 944 GNUNET_assert (GNUNET_TIME_timestamp_cmp (date, 945 ==, 946 wire_out_date)); 947 return GNUNET_OK; 948 } 949 950 951 /** 952 * Test API relating to wire_out handling. 953 * 954 * @param bd batch deposit to test 955 * @return #GNUNET_OK on success 956 */ 957 static enum GNUNET_GenericReturnValue 958 test_wire_out (const struct TALER_EXCHANGEDB_BatchDeposit *bd) 959 { 960 const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = &bd->cdis[0]; 961 struct TALER_FullPaytoHashP h_payto; 962 963 GNUNET_assert (0 < bd->num_cdis); 964 TALER_full_payto_hash (bd->receiver_wire_account, 965 &h_payto); 966 auditor_row_cnt = 0; 967 memset (&wire_out_wtid, 968 41, 969 sizeof (wire_out_wtid)); 970 wire_out_date = GNUNET_TIME_timestamp_get (); 971 GNUNET_assert (GNUNET_OK == 972 TALER_string_to_amount (CURRENCY ":1", 973 &wire_out_amount)); 974 975 /* we will transiently violate the wtid constraint on 976 the aggregation table, so we need to start the special 977 transaction where this is allowed... */ 978 FAILIF (GNUNET_OK != 979 plugin->start_deferred_wire_out (plugin->cls)); 980 981 /* setup values for wire transfer aggregation data */ 982 merchant_pub_wt = bd->merchant_pub; 983 h_contract_terms_wt = bd->h_contract_terms; 984 coin_pub_wt = deposit->coin.coin_pub; 985 986 coin_value_wt = deposit->amount_with_fee; 987 coin_fee_wt = global_fees.deposit; 988 GNUNET_assert (0 < 989 TALER_amount_subtract (&transfer_value_wt, 990 &coin_value_wt, 991 &coin_fee_wt)); 992 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 993 plugin->lookup_wire_transfer (plugin->cls, 994 &wire_out_wtid, 995 &cb_wt_never, 996 NULL)); 997 998 { 999 struct TALER_PrivateContractHashP h_contract_terms_wt2 = 1000 h_contract_terms_wt; 1001 bool pending; 1002 struct TALER_WireTransferIdentifierRawP wtid2; 1003 struct TALER_Amount coin_contribution2; 1004 struct TALER_Amount coin_fee2; 1005 struct GNUNET_TIME_Timestamp execution_time2; 1006 struct TALER_EXCHANGEDB_KycStatus kyc; 1007 union TALER_AccountPublicKeyP account_pub; 1008 1009 h_contract_terms_wt2.hash.bits[0]++; 1010 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1011 plugin->lookup_transfer_by_deposit (plugin->cls, 1012 &h_contract_terms_wt2, 1013 &h_wire_wt, 1014 &coin_pub_wt, 1015 &merchant_pub_wt, 1016 &pending, 1017 &wtid2, 1018 &execution_time2, 1019 &coin_contribution2, 1020 &coin_fee2, 1021 &kyc, 1022 &account_pub)); 1023 } 1024 { 1025 struct TALER_ReservePublicKeyP rpub; 1026 1027 memset (&rpub, 1028 44, 1029 sizeof (rpub)); 1030 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1031 plugin->store_wire_transfer_out (plugin->cls, 1032 wire_out_date, 1033 &wire_out_wtid, 1034 &h_payto, 1035 "my-config-section", 1036 &wire_out_amount)); 1037 } 1038 /* And now the commit should still succeed! */ 1039 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1040 plugin->commit (plugin->cls)); 1041 1042 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1043 plugin->lookup_wire_transfer (plugin->cls, 1044 &wire_out_wtid, 1045 &cb_wt_check, 1046 &cb_wt_never)); 1047 { 1048 bool pending; 1049 struct TALER_WireTransferIdentifierRawP wtid2; 1050 struct TALER_Amount coin_contribution2; 1051 struct TALER_Amount coin_fee2; 1052 struct GNUNET_TIME_Timestamp execution_time2; 1053 struct TALER_EXCHANGEDB_KycStatus kyc; 1054 union TALER_AccountPublicKeyP account_pub; 1055 1056 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1057 plugin->lookup_transfer_by_deposit (plugin->cls, 1058 &h_contract_terms_wt, 1059 &h_wire_wt, 1060 &coin_pub_wt, 1061 &merchant_pub_wt, 1062 &pending, 1063 &wtid2, 1064 &execution_time2, 1065 &coin_contribution2, 1066 &coin_fee2, 1067 &kyc, 1068 &account_pub)); 1069 GNUNET_assert (0 == GNUNET_memcmp (&wtid2, 1070 &wire_out_wtid)); 1071 GNUNET_assert (GNUNET_TIME_timestamp_cmp (execution_time2, 1072 ==, 1073 wire_out_date)); 1074 GNUNET_assert (0 == TALER_amount_cmp (&coin_contribution2, 1075 &coin_value_wt)); 1076 GNUNET_assert (0 == TALER_amount_cmp (&coin_fee2, 1077 &coin_fee_wt)); 1078 } 1079 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1080 plugin->select_wire_out_above_serial_id (plugin->cls, 1081 0, 1082 &audit_wire_cb, 1083 NULL)); 1084 FAILIF (1 != auditor_row_cnt); 1085 1086 return GNUNET_OK; 1087 drop: 1088 return GNUNET_SYSERR; 1089 } 1090 1091 1092 /** 1093 * Function called about recoups the exchange has to perform. 1094 * 1095 * @param cls closure with the expected value for @a coin_blind 1096 * @param rowid row identifier used to uniquely identify the recoup operation 1097 * @param timestamp when did we receive the recoup request 1098 * @param amount how much should be added back to the reserve 1099 * @param reserve_pub public key of the reserve 1100 * @param coin public information about the coin 1101 * @param denom_pub denomination key of @a coin 1102 * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP 1103 * @param coin_blind blinding factor used to blind the coin 1104 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 1105 */ 1106 static enum GNUNET_GenericReturnValue 1107 recoup_cb (void *cls, 1108 uint64_t rowid, 1109 struct GNUNET_TIME_Timestamp timestamp, 1110 const struct TALER_Amount *amount, 1111 const struct TALER_ReservePublicKeyP *reserve_pub, 1112 const struct TALER_CoinPublicInfo *coin, 1113 const struct TALER_DenominationPublicKey *denom_pub, 1114 const struct TALER_CoinSpendSignatureP *coin_sig, 1115 const union GNUNET_CRYPTO_BlindingSecretP *coin_blind) 1116 { 1117 const union GNUNET_CRYPTO_BlindingSecretP *cb = cls; 1118 1119 (void) rowid; 1120 (void) timestamp; 1121 (void) amount; 1122 (void) reserve_pub; 1123 (void) coin_sig; 1124 (void) coin; 1125 (void) denom_pub; 1126 FAILIF (NULL == cb); 1127 FAILIF (0 != GNUNET_memcmp (cb, 1128 coin_blind)); 1129 return GNUNET_OK; 1130 drop: 1131 return GNUNET_SYSERR; 1132 } 1133 1134 1135 /** 1136 * Function called on batch deposits that may require a 1137 * wire transfer. 1138 * 1139 * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *` 1140 * @param batch_deposit_serial_id where in the table are we 1141 * @param total_amount value of all missing deposits, including fees 1142 * @param wire_target_h_payto hash of the recipient account's payto URI 1143 * @param deadline what was the earliest requested wire transfer deadline 1144 */ 1145 static void 1146 wire_missing_cb ( 1147 void *cls, 1148 uint64_t batch_deposit_serial_id, 1149 const struct TALER_Amount *total_amount, 1150 const struct TALER_FullPaytoHashP *wire_target_h_payto, 1151 struct GNUNET_TIME_Timestamp deadline) 1152 { 1153 const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = cls; 1154 1155 (void) batch_deposit_serial_id; 1156 (void) deadline; 1157 (void) wire_target_h_payto; 1158 if (0 == 1159 TALER_amount_cmp (total_amount, 1160 &deposit->amount_with_fee)) 1161 result = 8; 1162 } 1163 1164 1165 /** 1166 * Callback invoked with information about refunds applicable 1167 * to a particular coin. 1168 * 1169 * @param cls closure with the `struct TALER_EXCHANGEDB_Refund *` we expect to get 1170 * @param amount_with_fee amount being refunded 1171 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 1172 */ 1173 static enum GNUNET_GenericReturnValue 1174 check_refund_cb (void *cls, 1175 const struct TALER_Amount *amount_with_fee) 1176 { 1177 const struct TALER_EXCHANGEDB_Refund *refund = cls; 1178 1179 if (0 != TALER_amount_cmp (amount_with_fee, 1180 &refund->details.refund_amount)) 1181 { 1182 GNUNET_break (0); 1183 result = 66; 1184 } 1185 return GNUNET_OK; 1186 } 1187 1188 1189 /** 1190 * Main function that will be run by the scheduler. 1191 * 1192 * @param cls closure with config 1193 */ 1194 static void 1195 run (void *cls) 1196 { 1197 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 1198 struct TALER_CoinSpendSignatureP coin_sig; 1199 struct GNUNET_TIME_Timestamp deadline; 1200 union GNUNET_CRYPTO_BlindingSecretP coin_blind; 1201 struct TALER_ReservePublicKeyP reserve_pub; 1202 struct TALER_ReservePublicKeyP reserve_pub2; 1203 struct TALER_ReservePublicKeyP reserve_pub3; 1204 struct DenomKeyPair *dkp = NULL; 1205 struct TALER_MasterSignatureP master_sig; 1206 struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; 1207 struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL; 1208 struct TALER_EXCHANGEDB_ReserveHistory *rh_head; 1209 struct TALER_EXCHANGEDB_BankTransfer *bt; 1210 struct TALER_EXCHANGEDB_Withdraw withdraw; 1211 struct TALER_HashBlindedPlanchetsP h_planchets; 1212 struct TALER_EXCHANGEDB_CoinDepositInformation deposit; 1213 struct TALER_EXCHANGEDB_BatchDeposit bd; 1214 struct TALER_CoinSpendPublicKeyP cpub2; 1215 struct TALER_MerchantPublicKeyP mpub2; 1216 struct TALER_EXCHANGEDB_Refund refund; 1217 const struct TALER_FullPayto sndr = { 1218 (char *) "payto://x-taler-bank/localhost:8080/1?receiver-name=1" 1219 }; 1220 const struct TALER_FullPayto rcvr = { 1221 (char *) "payto://x-taler-bank/localhost:8080/2?receiver-name=1" 1222 }; 1223 const uint32_t num_partitions = 10; 1224 unsigned int matched; 1225 enum GNUNET_DB_QueryStatus qs; 1226 struct GNUNET_TIME_Timestamp now; 1227 struct TALER_WireSaltP salt; 1228 struct TALER_CoinPubHashP c_hash; 1229 uint64_t known_coin_id; 1230 uint64_t rrc_serial; 1231 struct TALER_EXCHANGEDB_Refresh refresh; 1232 struct TALER_DenominationPublicKey *new_denom_pubs = NULL; 1233 uint64_t withdraw_serial_id; 1234 uint64_t melt_serial_id; 1235 struct TALER_PlanchetMasterSecretP ps; 1236 union GNUNET_CRYPTO_BlindingSecretP bks; 1237 struct TALER_Amount amount_with_fee; 1238 const struct TALER_ExchangeBlindingValues *alg_values 1239 = TALER_denom_ewv_rsa_singleton (); 1240 1241 memset (&deposit, 1242 0, 1243 sizeof (deposit)); 1244 memset (&bd, 1245 0, 1246 sizeof (bd)); 1247 bd.receiver_wire_account = rcvr; 1248 bd.cdis = &deposit; 1249 bd.num_cdis = 1; 1250 memset (&salt, 1251 45, 1252 sizeof (salt)); 1253 memset (&refresh, 1254 0, 1255 sizeof (refresh)); 1256 ZR_BLK (&cbc); 1257 ZR_BLK (&withdraw); 1258 if (NULL == 1259 (plugin = TALER_EXCHANGEDB_plugin_load (cfg, 1260 true))) 1261 { 1262 result = 77; 1263 return; 1264 } 1265 (void) plugin->drop_tables (plugin->cls); 1266 if (GNUNET_OK != 1267 plugin->create_tables (plugin->cls, 1268 true, 1269 num_partitions)) 1270 { 1271 result = 77; 1272 goto cleanup; 1273 } 1274 plugin->preflight (plugin->cls); 1275 FAILIF (GNUNET_OK != 1276 plugin->start (plugin->cls, 1277 "test-1")); 1278 1279 1280 /* test DB is empty */ 1281 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1282 plugin->select_recoup_above_serial_id (plugin->cls, 1283 0, 1284 &recoup_cb, 1285 NULL)); 1286 1287 /* simple extension check */ 1288 FAILIF (GNUNET_OK != 1289 test_extension_manifest ()); 1290 1291 RND_BLK (&reserve_pub); 1292 GNUNET_assert (GNUNET_OK == 1293 TALER_string_to_amount (CURRENCY ":1.000000", 1294 &global_amount)); 1295 GNUNET_assert (GNUNET_OK == 1296 TALER_string_to_amount (CURRENCY ":1.000010", 1297 &global_value)); 1298 GNUNET_assert (GNUNET_OK == 1299 TALER_string_to_amount (CURRENCY ":0.000010", 1300 &global_fees.withdraw)); 1301 GNUNET_assert (GNUNET_OK == 1302 TALER_string_to_amount (CURRENCY ":0.000010", 1303 &global_fees.deposit)); 1304 GNUNET_assert (GNUNET_OK == 1305 TALER_string_to_amount (CURRENCY ":0.000010", 1306 &global_fees.refresh)); 1307 GNUNET_assert (GNUNET_OK == 1308 TALER_string_to_amount (CURRENCY ":0.000010", 1309 &global_fees.refund)); 1310 GNUNET_assert (GNUNET_OK == 1311 TALER_string_to_amount (CURRENCY ":1.000010", 1312 &amount_with_fee)); 1313 result = 4; 1314 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1315 plugin->commit (plugin->cls)); 1316 now = GNUNET_TIME_timestamp_get (); 1317 { 1318 struct TALER_EXCHANGEDB_ReserveInInfo reserve = { 1319 .reserve_pub = &reserve_pub, 1320 .balance = &global_value, 1321 .execution_time = now, 1322 .sender_account_details = sndr, 1323 .exchange_account_name = "exchange-account-1", 1324 .wire_reference = 4 1325 }; 1326 enum GNUNET_DB_QueryStatus qsr; 1327 1328 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1329 plugin->reserves_in_insert (plugin->cls, 1330 &reserve, 1331 1, 1332 &qsr)); 1333 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1334 qsr); 1335 } 1336 FAILIF (GNUNET_OK != 1337 check_reserve (&reserve_pub, 1338 global_value.value, 1339 global_value.fraction, 1340 global_value.currency)); 1341 now = GNUNET_TIME_timestamp_get (); 1342 RND_BLK (&reserve_pub2); 1343 { 1344 struct TALER_EXCHANGEDB_ReserveInInfo reserve = { 1345 .reserve_pub = &reserve_pub2, 1346 .balance = &global_value, 1347 .execution_time = now, 1348 .sender_account_details = sndr, 1349 .exchange_account_name = "exchange-account-1", 1350 .wire_reference = 5 1351 }; 1352 enum GNUNET_DB_QueryStatus qsr; 1353 1354 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1355 plugin->reserves_in_insert (plugin->cls, 1356 &reserve, 1357 1, 1358 &qsr)); 1359 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1360 qsr); 1361 } 1362 FAILIF (GNUNET_OK != 1363 plugin->start (plugin->cls, 1364 "test-2")); 1365 FAILIF (GNUNET_OK != 1366 check_reserve (&reserve_pub, 1367 global_value.value, 1368 global_value.fraction, 1369 global_value.currency)); 1370 FAILIF (GNUNET_OK != 1371 check_reserve (&reserve_pub2, 1372 global_value.value, 1373 global_value.fraction, 1374 global_value.currency)); 1375 result = 5; 1376 now = GNUNET_TIME_timestamp_get (); 1377 dkp = create_denom_key_pair (RSA_KEY_SIZE, 1378 now, 1379 &global_value, 1380 &global_fees); 1381 GNUNET_assert (NULL != dkp); 1382 TALER_denom_pub_hash (&dkp->pub, 1383 &cbc.denom_pub_hash); 1384 RND_BLK (&cbc.reserve_sig); 1385 RND_BLK (&ps); 1386 TALER_planchet_blinding_secret_create (&ps, 1387 alg_values, 1388 &bks); 1389 { 1390 struct TALER_PlanchetDetail pd; 1391 struct TALER_CoinSpendPublicKeyP coin_pub; 1392 1393 1394 RND_BLK (&coin_pub); 1395 GNUNET_assert (GNUNET_OK == 1396 TALER_denom_blind (&dkp->pub, 1397 &bks, 1398 NULL, 1399 NULL, 1400 &coin_pub, 1401 alg_values, 1402 &c_hash, 1403 &pd.blinded_planchet)); 1404 TALER_coin_ev_hash (&pd.blinded_planchet, 1405 &cbc.denom_pub_hash, 1406 &cbc.h_coin_envelope); 1407 1408 GNUNET_assert ( 1409 GNUNET_OK == 1410 TALER_denom_sign_blinded ( 1411 &cbc.sig, 1412 &dkp->priv, 1413 false, 1414 &pd.blinded_planchet)); 1415 1416 TALER_wallet_blinded_planchets_hash ( 1417 1, 1418 &pd.blinded_planchet, 1419 &cbc.denom_pub_hash, 1420 &h_planchets); 1421 1422 TALER_blinded_planchet_free (&pd.blinded_planchet); 1423 } 1424 1425 cbc.reserve_pub = reserve_pub; 1426 cbc.amount_with_fee = global_value; 1427 GNUNET_assert (GNUNET_OK == 1428 TALER_amount_set_zero (CURRENCY, 1429 &cbc.withdraw_fee)); 1430 1431 { 1432 bool balance_ok; 1433 bool age_ok; 1434 bool idempotent; 1435 uint16_t noreveal_index; 1436 bool nonce_reuse; 1437 uint16_t maximum_age; 1438 uint32_t reserve_birthday; 1439 uint64_t denom_serial = 1; /* bold assumption */ 1440 struct TALER_Amount reserve_balance; 1441 struct TALER_BlindingMasterSeedP blinding_seed = {0}; 1442 struct GNUNET_CRYPTO_CSPublicRPairP cs_r_pubs = {0}; 1443 struct TALER_EXCHANGEDB_Withdraw withdraw_in = { 1444 .amount_with_fee = global_value, 1445 .age_proof_required = true, 1446 .max_age = 0, 1447 .noreveal_index = 42, 1448 .reserve_pub = reserve_pub, 1449 .reserve_sig = cbc.reserve_sig, 1450 .h_planchets = h_planchets, 1451 .no_blinding_seed = false, 1452 .blinding_seed = blinding_seed, 1453 .num_coins = 1, 1454 .h_coin_evs = &cbc.h_coin_envelope, 1455 .denom_sigs = &cbc.sig, 1456 .denom_serials = &denom_serial, 1457 .num_cs_r_pubs = 1, 1458 .cs_r_pubs = &cs_r_pubs, 1459 }; 1460 struct TALER_Amount zero_amount; 1461 1462 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1463 plugin->do_withdraw (plugin->cls, 1464 &withdraw_in, 1465 &now, 1466 &balance_ok, 1467 &reserve_balance, 1468 &age_ok, 1469 &maximum_age, 1470 &reserve_birthday, 1471 &idempotent, 1472 &noreveal_index, 1473 &nonce_reuse)); 1474 GNUNET_assert (! idempotent); 1475 GNUNET_assert (! nonce_reuse); 1476 GNUNET_assert (balance_ok); 1477 1478 1479 /** 1480 * Set the amount in the withdraw to zero, 1481 * to avoid triggering balance_ok issues for 1482 * the conflict and nonce_reuse tests. 1483 */ 1484 GNUNET_assert (GNUNET_OK == 1485 TALER_string_to_amount (CURRENCY ":0.000000", 1486 &zero_amount)); 1487 withdraw_in.amount_with_fee = zero_amount; 1488 1489 /** 1490 * Change some values to trigger conflict 1491 * due to h_planchet, not nonce. 1492 */ 1493 withdraw_in.blinding_seed.key_data[0] = 1; 1494 noreveal_index = -1; 1495 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1496 plugin->do_withdraw (plugin->cls, 1497 &withdraw_in, 1498 &now, 1499 &balance_ok, 1500 &reserve_balance, 1501 &age_ok, 1502 &maximum_age, 1503 &reserve_birthday, 1504 &idempotent, 1505 &noreveal_index, 1506 &nonce_reuse)); 1507 GNUNET_assert (! nonce_reuse); 1508 GNUNET_assert (idempotent); 1509 GNUNET_assert (42 == noreveal_index); 1510 1511 /** 1512 * Make h_planchet unique again, but trigger 1513 * conflict with blinding_seed. 1514 */ 1515 withdraw_in.blinding_seed.key_data[0] = 0; 1516 withdraw_in.h_planchets.hash.bits[0] += 1; 1517 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1518 plugin->do_withdraw (plugin->cls, 1519 &withdraw_in, 1520 &now, 1521 &balance_ok, 1522 &reserve_balance, 1523 &age_ok, 1524 &maximum_age, 1525 &reserve_birthday, 1526 &idempotent, 1527 &noreveal_index, 1528 &nonce_reuse)); 1529 GNUNET_assert (! idempotent); 1530 GNUNET_assert (nonce_reuse); 1531 } 1532 1533 FAILIF (GNUNET_OK != 1534 check_reserve (&reserve_pub, 1535 0, 1536 0, 1537 global_value.currency)); 1538 FAILIF (GNUNET_OK != 1539 check_reserve (&reserve_pub2, 1540 global_value.value, 1541 global_value.fraction, 1542 global_value.currency)); 1543 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1544 plugin->get_reserve_by_h_planchets (plugin->cls, 1545 &h_planchets, 1546 &reserve_pub3, 1547 &withdraw_serial_id)); 1548 FAILIF (0 != GNUNET_memcmp (&reserve_pub, 1549 &reserve_pub3)); 1550 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1551 plugin->get_withdraw (plugin->cls, 1552 &h_planchets, 1553 &withdraw)); 1554 FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_sig, 1555 &cbc.reserve_sig)); 1556 FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_pub, 1557 &cbc.reserve_pub)); 1558 result = 6; 1559 1560 { 1561 struct TALER_DenominationSignature ds; 1562 1563 GNUNET_assert (GNUNET_OK == 1564 TALER_denom_sig_unblind (&ds, 1565 &withdraw.denom_sigs[0], 1566 &bks, 1567 &c_hash, 1568 alg_values, 1569 &dkp->pub)); 1570 FAILIF (GNUNET_OK != 1571 TALER_denom_pub_verify (&dkp->pub, 1572 &ds, 1573 &c_hash)); 1574 TALER_denom_sig_free (&ds); 1575 } 1576 1577 RND_BLK (&coin_sig); 1578 RND_BLK (&coin_blind); 1579 RND_BLK (&deposit.coin.coin_pub); 1580 TALER_denom_pub_hash (&dkp->pub, 1581 &deposit.coin.denom_pub_hash); 1582 GNUNET_assert (GNUNET_OK == 1583 TALER_denom_sig_unblind (&deposit.coin.denom_sig, 1584 &cbc.sig, 1585 &bks, 1586 &c_hash, 1587 alg_values, 1588 &dkp->pub)); 1589 deadline = GNUNET_TIME_timestamp_get (); 1590 { 1591 struct TALER_DenominationHashP dph; 1592 struct TALER_AgeCommitmentHashP agh; 1593 1594 FAILIF (TALER_EXCHANGEDB_CKS_ADDED != 1595 plugin->ensure_coin_known (plugin->cls, 1596 &deposit.coin, 1597 &known_coin_id, 1598 &dph, 1599 &agh)); 1600 } 1601 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1602 plugin->commit (plugin->cls)); 1603 { 1604 struct GNUNET_TIME_Timestamp deposit_timestamp 1605 = GNUNET_TIME_timestamp_get (); 1606 bool balance_ok; 1607 uint32_t bad_balance_idx; 1608 bool in_conflict; 1609 struct TALER_FullPaytoHashP h_payto; 1610 1611 RND_BLK (&h_payto); 1612 bd.refund_deadline 1613 = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS); 1614 bd.wire_deadline 1615 = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS); 1616 deposit.amount_with_fee = global_value; 1617 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1618 plugin->do_deposit (plugin->cls, 1619 &bd, 1620 &deposit_timestamp, 1621 &balance_ok, 1622 &bad_balance_idx, 1623 &in_conflict)); 1624 FAILIF (! balance_ok); 1625 FAILIF (in_conflict); 1626 } 1627 1628 { 1629 bool not_found; 1630 bool refund_ok; 1631 bool gone; 1632 bool conflict; 1633 1634 refund.coin = deposit.coin; 1635 refund.details.merchant_pub = bd.merchant_pub; 1636 RND_BLK (&refund.details.merchant_sig); 1637 refund.details.h_contract_terms = bd.h_contract_terms; 1638 refund.details.rtransaction_id = 1; 1639 refund.details.refund_amount = global_value; 1640 refund.details.refund_fee = global_fees.refund; 1641 RND_BLK (&refund.details.merchant_sig); 1642 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1643 plugin->do_refund (plugin->cls, 1644 &refund, 1645 &global_fees.deposit, 1646 known_coin_id, 1647 ¬_found, 1648 &refund_ok, 1649 &gone, 1650 &conflict)); 1651 FAILIF (not_found); 1652 FAILIF (! refund_ok); 1653 FAILIF (gone); 1654 FAILIF (conflict); 1655 1656 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1657 plugin->select_refunds_by_coin (plugin->cls, 1658 &refund.coin.coin_pub, 1659 &refund.details.merchant_pub, 1660 &refund.details.h_contract_terms, 1661 &check_refund_cb, 1662 &refund)); 1663 } 1664 1665 1666 /* test do_refresh */ 1667 #pragma message "add refresh test for new refresh" 1668 #if 0 1669 { 1670 bool zombie_required = false; 1671 bool balance_ok; 1672 bool idempotent; 1673 uint16_t idem_noreveal_index; 1674 struct TALER_Amount insufficient_funds; 1675 struct TALER_EXCHANGEDB_Refresh_v26 refresh_v26; 1676 1677 refresh_v26.coin = deposit.coin; 1678 RND_BLK (&refresh_v26.coin_sig); 1679 RND_BLK (&refresh_v26.rc); 1680 refresh_v26.amount_with_fee = global_value; 1681 refresh_v26.noreveal_index = MELT_NOREVEAL_INDEX; 1682 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1683 plugin->do_refresh (plugin->cls, 1684 &refresh_v26, 1685 NULL, 1686 &idempotent, 1687 &idem_noreveal_index, 1688 &zombie_required, 1689 &balance_ok, 1690 &insufficient_funds)); 1691 FAILIF (! balance_ok); 1692 FAILIF (zombie_required); 1693 } 1694 #endif 1695 1696 1697 /* test do_melt */ 1698 { 1699 bool zombie_required = false; 1700 bool balance_ok; 1701 1702 refresh.coin = deposit.coin; 1703 RND_BLK (&refresh.coin_sig); 1704 RND_BLK (&refresh.rc); 1705 refresh.amount_with_fee = global_value; 1706 refresh.noreveal_index = MELT_NOREVEAL_INDEX; 1707 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1708 plugin->do_melt (plugin->cls, 1709 NULL, 1710 &refresh, 1711 known_coin_id, 1712 &zombie_required, 1713 &balance_ok)); 1714 FAILIF (! balance_ok); 1715 FAILIF (zombie_required); 1716 } 1717 1718 /* test get_melt */ 1719 { 1720 struct TALER_EXCHANGEDB_Melt ret_refresh_session; 1721 1722 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1723 plugin->get_melt (plugin->cls, 1724 &refresh.rc, 1725 &ret_refresh_session, 1726 &melt_serial_id)); 1727 FAILIF (refresh.noreveal_index != 1728 ret_refresh_session.session.noreveal_index); 1729 FAILIF (0 != 1730 TALER_amount_cmp (&refresh.amount_with_fee, 1731 &ret_refresh_session.session.amount_with_fee)); 1732 FAILIF (0 != 1733 TALER_amount_cmp (&global_fees.refresh, 1734 &ret_refresh_session.melt_fee)); 1735 FAILIF (0 != 1736 GNUNET_memcmp (&refresh.rc, 1737 &ret_refresh_session.session.rc)); 1738 FAILIF (0 != GNUNET_memcmp (&refresh.coin_sig, 1739 &ret_refresh_session.session.coin_sig)); 1740 FAILIF (0 != 1741 GNUNET_memcmp (&refresh.coin.coin_pub, 1742 &ret_refresh_session.session.coin.coin_pub)); 1743 FAILIF (0 != 1744 GNUNET_memcmp (&refresh.coin.denom_pub_hash, 1745 &ret_refresh_session.session.coin.denom_pub_hash)); 1746 } 1747 1748 { 1749 /* test 'select_refreshes_above_serial_id' */ 1750 auditor_row_cnt = 0; 1751 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1752 plugin->select_refreshes_above_serial_id (plugin->cls, 1753 0, 1754 &audit_refresh_session_cb, 1755 NULL)); 1756 FAILIF (1 != auditor_row_cnt); 1757 } 1758 1759 /* do refresh-reveal */ 1760 now = GNUNET_TIME_timestamp_get (); 1761 { 1762 new_dkp = GNUNET_new_array (MELT_NEW_COINS, 1763 struct DenomKeyPair *); 1764 new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, 1765 struct TALER_DenominationPublicKey); 1766 revealed_coins 1767 = GNUNET_new_array (MELT_NEW_COINS, 1768 struct TALER_EXCHANGEDB_RefreshRevealedCoin); 1769 for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) 1770 { 1771 struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin; 1772 struct GNUNET_CRYPTO_BlindedMessage *rp; 1773 struct GNUNET_CRYPTO_RsaBlindedMessage *rsa; 1774 struct TALER_BlindedPlanchet *bp; 1775 1776 new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, 1777 now, 1778 &global_value, 1779 &global_fees); 1780 GNUNET_assert (NULL != new_dkp[cnt]); 1781 new_denom_pubs[cnt] = new_dkp[cnt]->pub; 1782 ccoin = &revealed_coins[cnt]; 1783 bp = &ccoin->blinded_planchet; 1784 rp = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage); 1785 bp->blinded_message = rp; 1786 rp->cipher = GNUNET_CRYPTO_BSA_RSA; 1787 rp->rc = 1; 1788 rsa = &rp->details.rsa_blinded_message; 1789 rsa->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( 1790 GNUNET_CRYPTO_QUALITY_WEAK, 1791 (RSA_KEY_SIZE / 8) - 1); 1792 rsa->blinded_msg = GNUNET_malloc (rsa->blinded_msg_size); 1793 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 1794 rsa->blinded_msg, 1795 rsa->blinded_msg_size); 1796 TALER_denom_pub_hash (&new_dkp[cnt]->pub, 1797 &ccoin->h_denom_pub); 1798 TALER_denom_ewv_copy (&ccoin->exchange_vals, 1799 alg_values); 1800 TALER_coin_ev_hash (bp, 1801 &ccoin->h_denom_pub, 1802 &ccoin->coin_envelope_hash); 1803 GNUNET_assert (GNUNET_OK == 1804 TALER_denom_sign_blinded (&ccoin->coin_sig, 1805 &new_dkp[cnt]->priv, 1806 true, 1807 bp)); 1808 } 1809 RND_BLK (&tprivs); 1810 RND_BLK (&tpub); 1811 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1812 plugin->get_refresh_reveal (plugin->cls, 1813 &refresh.rc, 1814 &never_called_cb, 1815 NULL)); 1816 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1817 plugin->insert_refresh_reveal (plugin->cls, 1818 melt_serial_id, 1819 MELT_NEW_COINS, 1820 revealed_coins, 1821 TALER_CNC_KAPPA - 1, 1822 tprivs, 1823 &tpub)); 1824 { 1825 struct TALER_BlindedCoinHashP h_coin_ev; 1826 struct TALER_CoinSpendPublicKeyP ocp; 1827 struct TALER_DenominationHashP denom_hash; 1828 1829 TALER_denom_pub_hash (&new_denom_pubs[0], 1830 &denom_hash); 1831 TALER_coin_ev_hash (&revealed_coins[0].blinded_planchet, 1832 &denom_hash, 1833 &h_coin_ev); 1834 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1835 plugin->get_old_coin_by_h_blind (plugin->cls, 1836 &h_coin_ev, 1837 &ocp, 1838 &rrc_serial)); 1839 FAILIF (0 != 1840 GNUNET_memcmp (&ocp, 1841 &refresh.coin.coin_pub)); 1842 } 1843 FAILIF (0 >= 1844 plugin->get_refresh_reveal (plugin->cls, 1845 &refresh.rc, 1846 &check_refresh_reveal_cb, 1847 NULL)); 1848 qs = plugin->get_link_data (plugin->cls, 1849 &refresh.coin.coin_pub, 1850 &handle_link_data_cb, 1851 NULL); 1852 FAILIF (0 >= qs); 1853 { 1854 /* Just to test fetching a coin with melt history */ 1855 struct TALER_EXCHANGEDB_TransactionList *tl; 1856 uint64_t etag; 1857 struct TALER_Amount balance; 1858 struct TALER_DenominationHashP h_denom_pub; 1859 1860 qs = plugin->get_coin_transactions (plugin->cls, 1861 true, 1862 &refresh.coin.coin_pub, 1863 0, 1864 0, 1865 &etag, 1866 &balance, 1867 &h_denom_pub, 1868 &tl); 1869 FAILIF (0 >= qs); 1870 FAILIF (NULL == tl); 1871 plugin->free_coin_transaction_list (plugin->cls, 1872 tl); 1873 } 1874 } 1875 1876 /* do recoup-refresh */ 1877 { 1878 struct GNUNET_TIME_Timestamp recoup_timestamp 1879 = GNUNET_TIME_timestamp_get (); 1880 union GNUNET_CRYPTO_BlindingSecretP coin_bks; 1881 uint64_t new_known_coin_id; 1882 struct TALER_CoinPublicInfo new_coin; 1883 struct TALER_DenominationHashP dph; 1884 struct TALER_AgeCommitmentHashP agh; 1885 bool recoup_ok; 1886 bool internal_failure; 1887 1888 new_coin = deposit.coin; /* steal basic data */ 1889 RND_BLK (&new_coin.coin_pub); 1890 FAILIF (TALER_EXCHANGEDB_CKS_ADDED != 1891 plugin->ensure_coin_known (plugin->cls, 1892 &new_coin, 1893 &new_known_coin_id, 1894 &dph, 1895 &agh)); 1896 RND_BLK (&coin_bks); 1897 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1898 plugin->do_recoup_refresh (plugin->cls, 1899 &deposit.coin.coin_pub, 1900 rrc_serial, 1901 &coin_bks, 1902 &new_coin.coin_pub, 1903 new_known_coin_id, 1904 &coin_sig, 1905 &recoup_timestamp, 1906 &recoup_ok, 1907 &internal_failure)); 1908 FAILIF (! recoup_ok); 1909 FAILIF (internal_failure); 1910 } 1911 1912 /* do recoup */ 1913 { 1914 struct TALER_EXCHANGEDB_Reserve pre_reserve; 1915 struct TALER_EXCHANGEDB_Reserve post_reserve; 1916 struct TALER_Amount delta; 1917 bool recoup_ok; 1918 bool internal_failure; 1919 struct GNUNET_TIME_Timestamp recoup_timestamp 1920 = GNUNET_TIME_timestamp_get (); 1921 1922 pre_reserve.pub = reserve_pub; 1923 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1924 plugin->reserves_get (plugin->cls, 1925 &pre_reserve)); 1926 FAILIF (! TALER_amount_is_zero (&pre_reserve.balance)); 1927 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1928 plugin->do_recoup (plugin->cls, 1929 &reserve_pub, 1930 withdraw_serial_id, 1931 &coin_blind, 1932 &deposit.coin.coin_pub, 1933 known_coin_id, 1934 &coin_sig, 1935 &recoup_timestamp, 1936 &recoup_ok, 1937 &internal_failure)); 1938 FAILIF (internal_failure); 1939 FAILIF (! recoup_ok); 1940 post_reserve.pub = reserve_pub; 1941 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1942 plugin->reserves_get (plugin->cls, 1943 &post_reserve)); 1944 FAILIF (0 >= 1945 TALER_amount_subtract (&delta, 1946 &post_reserve.balance, 1947 &pre_reserve.balance)); 1948 FAILIF (0 != 1949 TALER_amount_cmp (&delta, 1950 &global_value)); 1951 } 1952 1953 FAILIF (GNUNET_OK != 1954 plugin->start (plugin->cls, 1955 "test-3")); 1956 1957 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1958 plugin->select_recoup_above_serial_id (plugin->cls, 1959 0, 1960 &recoup_cb, 1961 &coin_blind)); 1962 /* Do reserve close */ 1963 now = GNUNET_TIME_timestamp_get (); 1964 GNUNET_assert (GNUNET_OK == 1965 TALER_string_to_amount (CURRENCY ":0.000010", 1966 &fee_closing)); 1967 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1968 plugin->insert_reserve_closed (plugin->cls, 1969 &reserve_pub2, 1970 now, 1971 sndr, 1972 &wire_out_wtid, 1973 &amount_with_fee, 1974 &fee_closing, 1975 0)); 1976 FAILIF (GNUNET_OK != 1977 check_reserve (&reserve_pub2, 1978 0, 1979 0, 1980 global_value.currency)); 1981 now = GNUNET_TIME_timestamp_get (); 1982 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1983 plugin->insert_reserve_closed (plugin->cls, 1984 &reserve_pub, 1985 now, 1986 sndr, 1987 &wire_out_wtid, 1988 &global_value, 1989 &fee_closing, 1990 0)); 1991 FAILIF (GNUNET_OK != 1992 check_reserve (&reserve_pub, 1993 0, 1994 0, 1995 global_value.currency)); 1996 result = 7; 1997 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1998 plugin->commit (plugin->cls)); 1999 2000 2001 /* check reserve history */ 2002 { 2003 struct TALER_Amount balance; 2004 uint64_t etag_out; 2005 2006 qs = plugin->get_reserve_history (plugin->cls, 2007 &reserve_pub, 2008 0, 2009 0, 2010 &etag_out, 2011 &balance, 2012 &rh); 2013 } 2014 FAILIF (0 > qs); 2015 FAILIF (NULL == rh); 2016 rh_head = rh; 2017 { 2018 unsigned int cnt; 2019 2020 for (cnt = 0; 2021 NULL != rh_head; 2022 rh_head = rh_head->next, cnt++) 2023 { 2024 switch (rh_head->type) 2025 { 2026 case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: 2027 bt = rh_head->details.bank; 2028 FAILIF (0 != 2029 GNUNET_memcmp (&bt->reserve_pub, 2030 &reserve_pub)); 2031 /* this is the amount we transferred twice*/ 2032 FAILIF (1 != bt->amount.value); 2033 FAILIF (1000 != bt->amount.fraction); 2034 FAILIF (0 != strcmp (CURRENCY, 2035 bt->amount.currency)); 2036 FAILIF (NULL == bt->sender_account_details.full_payto); 2037 break; 2038 case TALER_EXCHANGEDB_RO_WITHDRAW_COINS: 2039 { 2040 struct TALER_EXCHANGEDB_Withdraw *rh_withdraw = 2041 rh_head->details.withdraw; 2042 FAILIF (0 != 2043 GNUNET_memcmp (&rh_withdraw->reserve_pub, 2044 &reserve_pub)); 2045 #pragma message "maybe more tests!?" 2046 } 2047 break; 2048 case TALER_EXCHANGEDB_RO_RECOUP_COIN: 2049 { 2050 struct TALER_EXCHANGEDB_Recoup *recoup = rh_head->details.recoup; 2051 2052 FAILIF (0 != 2053 GNUNET_memcmp (&recoup->coin_sig, 2054 &coin_sig)); 2055 FAILIF (0 != 2056 GNUNET_memcmp (&recoup->coin_blind, 2057 &coin_blind)); 2058 FAILIF (0 != 2059 GNUNET_memcmp (&recoup->reserve_pub, 2060 &reserve_pub)); 2061 FAILIF (0 != 2062 GNUNET_memcmp (&recoup->coin.coin_pub, 2063 &deposit.coin.coin_pub)); 2064 FAILIF (0 != 2065 TALER_amount_cmp (&recoup->value, 2066 &global_value)); 2067 } 2068 break; 2069 case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK: 2070 { 2071 struct TALER_EXCHANGEDB_ClosingTransfer *closing 2072 = rh_head->details.closing; 2073 2074 FAILIF (0 != 2075 GNUNET_memcmp (&closing->reserve_pub, 2076 &reserve_pub)); 2077 FAILIF (0 != TALER_amount_cmp (&closing->amount, 2078 &amount_with_fee)); 2079 FAILIF (0 != TALER_amount_cmp (&closing->closing_fee, 2080 &fee_closing)); 2081 } 2082 break; 2083 case TALER_EXCHANGEDB_RO_PURSE_MERGE: 2084 { 2085 /* FIXME: not yet tested */ 2086 break; 2087 } 2088 case TALER_EXCHANGEDB_RO_HISTORY_REQUEST: 2089 { 2090 /* FIXME: not yet tested */ 2091 break; 2092 } 2093 case TALER_EXCHANGEDB_RO_OPEN_REQUEST: 2094 { 2095 /* FIXME: not yet tested */ 2096 break; 2097 } 2098 case TALER_EXCHANGEDB_RO_CLOSE_REQUEST: 2099 { 2100 /* FIXME: not yet tested */ 2101 break; 2102 } 2103 } 2104 } 2105 GNUNET_assert (4 == cnt); 2106 FAILIF (4 != cnt); 2107 } 2108 2109 auditor_row_cnt = 0; 2110 FAILIF (0 >= 2111 plugin->select_reserves_in_above_serial_id (plugin->cls, 2112 0, 2113 &audit_reserve_in_cb, 2114 NULL)); 2115 FAILIF (0 >= 2116 plugin->select_withdrawals_above_serial_id (plugin->cls, 2117 0, 2118 &audit_reserve_out_cb, 2119 NULL)); 2120 FAILIF (3 != auditor_row_cnt); 2121 2122 2123 auditor_row_cnt = 0; 2124 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2125 plugin->select_refunds_above_serial_id (plugin->cls, 2126 0, 2127 &audit_refund_cb, 2128 NULL)); 2129 FAILIF (1 != auditor_row_cnt); 2130 { 2131 uint64_t etag = 0; 2132 struct TALER_Amount balance; 2133 struct TALER_DenominationHashP h_denom_pub; 2134 struct TALER_EXCHANGEDB_TransactionList *tl; 2135 2136 qs = plugin->get_coin_transactions (plugin->cls, 2137 true, 2138 &refund.coin.coin_pub, 2139 0, 2140 0, 2141 &etag, 2142 &balance, 2143 &h_denom_pub, 2144 &tl); 2145 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs); 2146 GNUNET_assert (NULL != tl); 2147 matched = 0; 2148 for (struct TALER_EXCHANGEDB_TransactionList *tlp = tl; 2149 NULL != tlp; 2150 tlp = tlp->next) 2151 { 2152 switch (tlp->type) 2153 { 2154 case TALER_EXCHANGEDB_TT_DEPOSIT: 2155 { 2156 struct TALER_EXCHANGEDB_DepositListEntry *have = tlp->details.deposit; 2157 2158 /* Note: we're not comparing the denomination keys, as there is 2159 still the question of whether we should even bother exporting 2160 them here. */ 2161 FAILIF (0 != 2162 GNUNET_memcmp (&have->csig, 2163 &deposit.csig)); 2164 FAILIF (0 != 2165 GNUNET_memcmp (&have->merchant_pub, 2166 &bd.merchant_pub)); 2167 FAILIF (0 != 2168 GNUNET_memcmp (&have->h_contract_terms, 2169 &bd.h_contract_terms)); 2170 FAILIF (0 != 2171 GNUNET_memcmp (&have->wire_salt, 2172 &bd.wire_salt)); 2173 FAILIF (GNUNET_TIME_timestamp_cmp (have->timestamp, 2174 !=, 2175 bd.wallet_timestamp)); 2176 FAILIF (GNUNET_TIME_timestamp_cmp (have->refund_deadline, 2177 !=, 2178 bd.refund_deadline)); 2179 FAILIF (GNUNET_TIME_timestamp_cmp (have->wire_deadline, 2180 !=, 2181 bd.wire_deadline)); 2182 FAILIF (0 != TALER_amount_cmp (&have->amount_with_fee, 2183 &deposit.amount_with_fee)); 2184 matched |= 1; 2185 break; 2186 } 2187 /* this coin pub was actually never melted... */ 2188 case TALER_EXCHANGEDB_TT_MELT: 2189 FAILIF (0 != 2190 GNUNET_memcmp (&refresh.rc, 2191 &tlp->details.melt->rc)); 2192 matched |= 2; 2193 break; 2194 case TALER_EXCHANGEDB_TT_REFUND: 2195 { 2196 struct TALER_EXCHANGEDB_RefundListEntry *have = tlp->details.refund; 2197 2198 /* Note: we're not comparing the denomination keys, as there is 2199 still the question of whether we should even bother exporting 2200 them here. */ 2201 FAILIF (0 != GNUNET_memcmp (&have->merchant_pub, 2202 &refund.details.merchant_pub)); 2203 FAILIF (0 != GNUNET_memcmp (&have->merchant_sig, 2204 &refund.details.merchant_sig)); 2205 FAILIF (0 != GNUNET_memcmp (&have->h_contract_terms, 2206 &refund.details.h_contract_terms)); 2207 FAILIF (have->rtransaction_id != refund.details.rtransaction_id); 2208 FAILIF (0 != TALER_amount_cmp (&have->refund_amount, 2209 &refund.details.refund_amount)); 2210 FAILIF (0 != TALER_amount_cmp (&have->refund_fee, 2211 &refund.details.refund_fee)); 2212 matched |= 4; 2213 break; 2214 } 2215 case TALER_EXCHANGEDB_TT_RECOUP: 2216 { 2217 struct TALER_EXCHANGEDB_RecoupListEntry *recoup = 2218 tlp->details.recoup; 2219 2220 FAILIF (0 != GNUNET_memcmp (&recoup->coin_sig, 2221 &coin_sig)); 2222 FAILIF (0 != GNUNET_memcmp (&recoup->coin_blind, 2223 &coin_blind)); 2224 FAILIF (0 != GNUNET_memcmp (&recoup->reserve_pub, 2225 &reserve_pub)); 2226 FAILIF (0 != TALER_amount_cmp (&recoup->value, 2227 &global_value)); 2228 matched |= 8; 2229 break; 2230 } 2231 case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP: 2232 /* FIXME: check fields better... */ 2233 #pragma \ 2234 message "TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP case doesn't work right now" 2235 matched |= 16; 2236 break; 2237 default: 2238 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2239 "Unexpected coin history transaction type: %d\n", 2240 tlp->type); 2241 FAILIF (1); 2242 break; 2243 } 2244 } 2245 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2246 "matched=%d, SKIPPING FAILIF(31 != matched) FOR NOW\n", 2247 matched); 2248 #pragma message "skipping FAILIF(31 != matched) check for now" 2249 #if 0 2250 FAILIF (31 != matched); 2251 #endif 2252 2253 plugin->free_coin_transaction_list (plugin->cls, 2254 tl); 2255 } 2256 2257 /* Tests for deposits+wire */ 2258 TALER_denom_sig_free (&deposit.coin.denom_sig); 2259 memset (&deposit, 2260 0, 2261 sizeof (deposit)); 2262 RND_BLK (&deposit.coin.coin_pub); 2263 TALER_denom_pub_hash (&dkp->pub, 2264 &deposit.coin.denom_pub_hash); 2265 GNUNET_assert (GNUNET_OK == 2266 TALER_denom_sig_unblind (&deposit.coin.denom_sig, 2267 &cbc.sig, 2268 &bks, 2269 &c_hash, 2270 alg_values, 2271 &dkp->pub)); 2272 RND_BLK (&deposit.csig); 2273 RND_BLK (&bd.merchant_pub); 2274 RND_BLK (&bd.h_contract_terms); 2275 RND_BLK (&bd.wire_salt); 2276 bd.receiver_wire_account.full_payto = 2277 (char *) "payto://iban/DE67830654080004822650?receiver-name=Test"; 2278 TALER_merchant_wire_signature_hash ( 2279 bd.receiver_wire_account, 2280 &bd.wire_salt, 2281 &h_wire_wt); 2282 deposit.amount_with_fee = global_value; 2283 bd.refund_deadline = deadline; 2284 bd.wire_deadline = deadline; 2285 result = 8; 2286 FAILIF (GNUNET_OK != 2287 plugin->start (plugin->cls, 2288 "test-3")); 2289 { 2290 uint64_t known_coin_id2; 2291 struct TALER_DenominationHashP dph; 2292 struct TALER_AgeCommitmentHashP agh; 2293 2294 FAILIF (TALER_EXCHANGEDB_CKS_ADDED != 2295 plugin->ensure_coin_known (plugin->cls, 2296 &deposit.coin, 2297 &known_coin_id2, 2298 &dph, 2299 &agh)); 2300 } 2301 now = GNUNET_TIME_timestamp_get (); 2302 { 2303 struct GNUNET_TIME_Timestamp r; 2304 struct TALER_Amount deposit_fee; 2305 struct TALER_MerchantWireHashP h_wire; 2306 bool balance_ok; 2307 uint32_t bad_idx; 2308 bool ctr_conflict; 2309 2310 TALER_full_payto_hash (bd.receiver_wire_account, 2311 &bd.wire_target_h_payto); 2312 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2313 plugin->do_deposit (plugin->cls, 2314 &bd, 2315 &now, 2316 &balance_ok, 2317 &bad_idx, 2318 &ctr_conflict)); 2319 TALER_merchant_wire_signature_hash (bd.receiver_wire_account, 2320 &bd.wire_salt, 2321 &h_wire); 2322 FAILIF (1 != 2323 plugin->have_deposit2 (plugin->cls, 2324 &bd.h_contract_terms, 2325 &h_wire, 2326 &deposit.coin.coin_pub, 2327 &bd.merchant_pub, 2328 bd.refund_deadline, 2329 &deposit_fee, 2330 &r)); 2331 FAILIF (GNUNET_TIME_timestamp_cmp (now, 2332 !=, 2333 r)); 2334 } 2335 { 2336 result = 66; 2337 FAILIF (0 >= 2338 plugin->select_batch_deposits_missing_wire (plugin->cls, 2339 0, 2340 &wire_missing_cb, 2341 &deposit)); 2342 FAILIF (8 != result); 2343 } 2344 auditor_row_cnt = 0; 2345 FAILIF (0 >= 2346 plugin->select_coin_deposits_above_serial_id (plugin->cls, 2347 0, 2348 &audit_deposit_cb, 2349 NULL)); 2350 FAILIF (0 == auditor_row_cnt); 2351 result = 8; 2352 sleep (2); /* give deposit time to be ready */ 2353 { 2354 struct TALER_MerchantPublicKeyP merchant_pub2; 2355 struct TALER_FullPayto payto_uri2; 2356 2357 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2358 plugin->get_ready_deposit (plugin->cls, 2359 0, 2360 INT32_MAX, 2361 &merchant_pub2, 2362 &payto_uri2)); 2363 FAILIF (0 != GNUNET_memcmp (&merchant_pub2, 2364 &bd.merchant_pub)); 2365 FAILIF (0 != TALER_full_payto_cmp (payto_uri2, 2366 bd.receiver_wire_account)); 2367 TALER_full_payto_hash (payto_uri2, 2368 &global_wire_target_h_payto); 2369 GNUNET_free (payto_uri2.full_payto); 2370 } 2371 2372 { 2373 struct TALER_Amount total; 2374 struct TALER_WireTransferIdentifierRawP wtid; 2375 2376 memset (&wtid, 2377 41, 2378 sizeof (wtid)); 2379 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2380 plugin->aggregate (plugin->cls, 2381 &global_wire_target_h_payto, 2382 &bd.merchant_pub, 2383 &wtid, 2384 &total)); 2385 } 2386 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2387 plugin->commit (plugin->cls)); 2388 FAILIF (GNUNET_OK != 2389 plugin->start (plugin->cls, 2390 "test-3")); 2391 { 2392 struct TALER_WireTransferIdentifierRawP wtid; 2393 struct TALER_Amount total; 2394 struct TALER_WireTransferIdentifierRawP wtid2; 2395 struct TALER_Amount total2; 2396 2397 memset (&wtid, 2398 42, 2399 sizeof (wtid)); 2400 GNUNET_assert (GNUNET_OK == 2401 TALER_string_to_amount (CURRENCY ":42", 2402 &total)); 2403 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2404 plugin->select_aggregation_transient ( 2405 plugin->cls, 2406 &global_wire_target_h_payto, 2407 &bd.merchant_pub, 2408 "x-bank", 2409 &wtid2, 2410 &total2)); 2411 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2412 plugin->create_aggregation_transient ( 2413 plugin->cls, 2414 &global_wire_target_h_payto, 2415 "x-bank", 2416 &bd.merchant_pub, 2417 &wtid, 2418 0, 2419 &total)); 2420 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2421 plugin->select_aggregation_transient ( 2422 plugin->cls, 2423 &global_wire_target_h_payto, 2424 &bd.merchant_pub, 2425 "x-bank", 2426 &wtid2, 2427 &total2)); 2428 FAILIF (0 != 2429 GNUNET_memcmp (&wtid2, 2430 &wtid)); 2431 FAILIF (0 != 2432 TALER_amount_cmp (&total2, 2433 &total)); 2434 GNUNET_assert (GNUNET_OK == 2435 TALER_string_to_amount (CURRENCY ":43", 2436 &total)); 2437 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2438 plugin->update_aggregation_transient ( 2439 plugin->cls, 2440 &global_wire_target_h_payto, 2441 &wtid, 2442 0, 2443 &total)); 2444 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2445 plugin->select_aggregation_transient ( 2446 plugin->cls, 2447 &global_wire_target_h_payto, 2448 &bd.merchant_pub, 2449 "x-bank", 2450 &wtid2, 2451 &total2)); 2452 FAILIF (0 != 2453 GNUNET_memcmp (&wtid2, 2454 &wtid)); 2455 FAILIF (0 != 2456 TALER_amount_cmp (&total2, 2457 &total)); 2458 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2459 plugin->delete_aggregation_transient ( 2460 plugin->cls, 2461 &global_wire_target_h_payto, 2462 &wtid)); 2463 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2464 plugin->select_aggregation_transient ( 2465 plugin->cls, 2466 &global_wire_target_h_payto, 2467 &bd.merchant_pub, 2468 "x-bank", 2469 &wtid2, 2470 &total2)); 2471 } 2472 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2473 plugin->commit (plugin->cls)); 2474 2475 result = 10; 2476 FAILIF (GNUNET_OK != 2477 plugin->start (plugin->cls, 2478 "test-2")); 2479 RND_BLK (&mpub2); /* should fail if merchant is different */ 2480 { 2481 struct TALER_MerchantWireHashP h_wire; 2482 struct GNUNET_TIME_Timestamp r; 2483 struct TALER_Amount deposit_fee; 2484 2485 TALER_merchant_wire_signature_hash (bd.receiver_wire_account, 2486 &bd.wire_salt, 2487 &h_wire); 2488 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2489 plugin->have_deposit2 (plugin->cls, 2490 &bd.h_contract_terms, 2491 &h_wire, 2492 &deposit.coin.coin_pub, 2493 &mpub2, 2494 bd.refund_deadline, 2495 &deposit_fee, 2496 &r)); 2497 RND_BLK (&cpub2); /* should fail if coin is different */ 2498 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2499 plugin->have_deposit2 (plugin->cls, 2500 &bd.h_contract_terms, 2501 &h_wire, 2502 &cpub2, 2503 &bd.merchant_pub, 2504 bd.refund_deadline, 2505 &deposit_fee, 2506 &r)); 2507 } 2508 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2509 plugin->commit (plugin->cls)); 2510 2511 2512 /* test revocation */ 2513 FAILIF (GNUNET_OK != 2514 plugin->start (plugin->cls, 2515 "test-3b")); 2516 RND_BLK (&master_sig); 2517 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2518 plugin->insert_denomination_revocation (plugin->cls, 2519 &cbc.denom_pub_hash, 2520 &master_sig)); 2521 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2522 plugin->commit (plugin->cls)); 2523 plugin->preflight (plugin->cls); 2524 FAILIF (GNUNET_OK != 2525 plugin->start (plugin->cls, 2526 "test-4")); 2527 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2528 plugin->insert_denomination_revocation (plugin->cls, 2529 &cbc.denom_pub_hash, 2530 &master_sig)); 2531 plugin->rollback (plugin->cls); 2532 plugin->preflight (plugin->cls); 2533 FAILIF (GNUNET_OK != 2534 plugin->start (plugin->cls, 2535 "test-5")); 2536 { 2537 struct TALER_MasterSignatureP msig; 2538 uint64_t rev_rowid; 2539 2540 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2541 plugin->get_denomination_revocation (plugin->cls, 2542 &cbc.denom_pub_hash, 2543 &msig, 2544 &rev_rowid)); 2545 FAILIF (0 != GNUNET_memcmp (&msig, 2546 &master_sig)); 2547 } 2548 2549 2550 plugin->rollback (plugin->cls); 2551 FAILIF (GNUNET_OK != 2552 test_wire_prepare ()); 2553 FAILIF (GNUNET_OK != 2554 test_wire_out (&bd)); 2555 FAILIF (GNUNET_OK != 2556 test_gc ()); 2557 FAILIF (GNUNET_OK != 2558 test_wire_fees ()); 2559 2560 plugin->preflight (plugin->cls); 2561 2562 result = 0; 2563 2564 drop: 2565 if (0 != result) 2566 plugin->rollback (plugin->cls); 2567 if (NULL != rh) 2568 plugin->free_reserve_history (plugin->cls, 2569 rh); 2570 rh = NULL; 2571 GNUNET_break (GNUNET_OK == 2572 plugin->drop_tables (plugin->cls)); 2573 cleanup: 2574 if (NULL != dkp) 2575 destroy_denom_key_pair (dkp); 2576 if (NULL != revealed_coins) 2577 { 2578 for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) 2579 { 2580 TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig); 2581 TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet); 2582 } 2583 GNUNET_free (revealed_coins); 2584 revealed_coins = NULL; 2585 } 2586 GNUNET_free (new_denom_pubs); 2587 for (unsigned int cnt = 0; 2588 (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]); 2589 cnt++) 2590 destroy_denom_key_pair (new_dkp[cnt]); 2591 GNUNET_free (new_dkp); 2592 TALER_denom_sig_free (&deposit.coin.denom_sig); 2593 TALER_blinded_denom_sig_free (&cbc.sig); 2594 TALER_blinded_denom_sig_free (withdraw.denom_sigs); 2595 dkp = NULL; 2596 TALER_EXCHANGEDB_plugin_unload (plugin); 2597 plugin = NULL; 2598 } 2599 2600 2601 int 2602 main (int argc, 2603 char *const argv[]) 2604 { 2605 const char *plugin_name; 2606 char *config_filename; 2607 char *testname; 2608 struct GNUNET_CONFIGURATION_Handle *cfg; 2609 2610 (void) argc; 2611 result = -1; 2612 if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) 2613 { 2614 GNUNET_break (0); 2615 return -1; 2616 } 2617 GNUNET_log_setup (argv[0], 2618 "INFO", 2619 NULL); 2620 plugin_name++; 2621 (void) GNUNET_asprintf (&testname, 2622 "test-exchange-db-%s", 2623 plugin_name); 2624 (void) GNUNET_asprintf (&config_filename, 2625 "%s.conf", 2626 testname); 2627 cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ()); 2628 if (GNUNET_OK != 2629 GNUNET_CONFIGURATION_parse (cfg, 2630 config_filename)) 2631 { 2632 GNUNET_break (0); 2633 GNUNET_free (config_filename); 2634 GNUNET_free (testname); 2635 return 2; 2636 } 2637 GNUNET_SCHEDULER_run (&run, 2638 cfg); 2639 GNUNET_CONFIGURATION_destroy (cfg); 2640 GNUNET_free (config_filename); 2641 GNUNET_free (testname); 2642 return result; 2643 } 2644 2645 2646 /* end of test_exchangedb.c */