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