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