test_exchangedb.c (94093B)
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 (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 (&master_sig, 892 sizeof (master_sig)); 893 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 894 plugin->insert_wire_fee (plugin->cls, 895 "wire-method", 896 start_date, 897 end_date, 898 &fees, 899 &master_sig)) 900 { 901 GNUNET_break (0); 902 return GNUNET_SYSERR; 903 } 904 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 905 plugin->insert_wire_fee (plugin->cls, 906 "wire-method", 907 start_date, 908 end_date, 909 &fees, 910 &master_sig)) 911 { 912 GNUNET_break (0); 913 return GNUNET_SYSERR; 914 } 915 /* This must fail as 'end_date' is NOT in the 916 half-open interval [start_date,end_date) */ 917 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 918 plugin->get_wire_fee (plugin->cls, 919 "wire-method", 920 end_date, 921 &rowid, 922 &sd, 923 &ed, 924 &fees2, 925 &ms)) 926 { 927 GNUNET_break (0); 928 return GNUNET_SYSERR; 929 } 930 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 931 plugin->get_wire_fee (plugin->cls, 932 "wire-method", 933 start_date, 934 &rowid, 935 &sd, 936 &ed, 937 &fees2, 938 &ms)) 939 { 940 GNUNET_break (0); 941 return GNUNET_SYSERR; 942 } 943 if ( (GNUNET_TIME_timestamp_cmp (sd, 944 !=, 945 start_date)) || 946 (GNUNET_TIME_timestamp_cmp (ed, 947 !=, 948 end_date)) || 949 (0 != TALER_wire_fee_set_cmp (&fees, 950 &fees2)) || 951 (0 != GNUNET_memcmp (&ms, 952 &master_sig)) ) 953 { 954 GNUNET_break (0); 955 return GNUNET_SYSERR; 956 } 957 return GNUNET_OK; 958 } 959 960 961 static struct TALER_Amount wire_out_amount; 962 963 964 /** 965 * Callback with data about an executed wire transfer. 966 * 967 * @param cls closure 968 * @param rowid identifier of the respective row in the database 969 * @param date timestamp of the wire transfer (roughly) 970 * @param wtid wire transfer subject 971 * @param wire wire transfer details of the receiver 972 * @param amount amount that was wired 973 * @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration 974 */ 975 static enum GNUNET_GenericReturnValue 976 audit_wire_cb (void *cls, 977 uint64_t rowid, 978 struct GNUNET_TIME_Timestamp date, 979 const struct TALER_WireTransferIdentifierRawP *wtid, 980 const struct TALER_FullPayto payto_uri, 981 const struct TALER_Amount *amount) 982 { 983 (void) cls; 984 (void) rowid; 985 (void) payto_uri; 986 auditor_row_cnt++; 987 GNUNET_assert (0 == 988 TALER_amount_cmp (amount, 989 &wire_out_amount)); 990 GNUNET_assert (0 == 991 GNUNET_memcmp (wtid, 992 &wire_out_wtid)); 993 GNUNET_assert (GNUNET_TIME_timestamp_cmp (date, 994 ==, 995 wire_out_date)); 996 return GNUNET_OK; 997 } 998 999 1000 /** 1001 * Test API relating to wire_out handling. 1002 * 1003 * @param bd batch deposit to test 1004 * @return #GNUNET_OK on success 1005 */ 1006 static enum GNUNET_GenericReturnValue 1007 test_wire_out (const struct TALER_EXCHANGEDB_BatchDeposit *bd) 1008 { 1009 const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = &bd->cdis[0]; 1010 struct TALER_FullPaytoHashP h_payto; 1011 1012 GNUNET_assert (0 < bd->num_cdis); 1013 TALER_full_payto_hash (bd->receiver_wire_account, 1014 &h_payto); 1015 auditor_row_cnt = 0; 1016 memset (&wire_out_wtid, 1017 41, 1018 sizeof (wire_out_wtid)); 1019 wire_out_date = GNUNET_TIME_timestamp_get (); 1020 GNUNET_assert (GNUNET_OK == 1021 TALER_string_to_amount (CURRENCY ":1", 1022 &wire_out_amount)); 1023 1024 /* we will transiently violate the wtid constraint on 1025 the aggregation table, so we need to start the special 1026 transaction where this is allowed... */ 1027 FAILIF (GNUNET_OK != 1028 plugin->start_deferred_wire_out (plugin->cls)); 1029 1030 /* setup values for wire transfer aggregation data */ 1031 merchant_pub_wt = bd->merchant_pub; 1032 h_contract_terms_wt = bd->h_contract_terms; 1033 coin_pub_wt = deposit->coin.coin_pub; 1034 1035 coin_value_wt = deposit->amount_with_fee; 1036 coin_fee_wt = global_fees.deposit; 1037 GNUNET_assert (0 < 1038 TALER_amount_subtract (&transfer_value_wt, 1039 &coin_value_wt, 1040 &coin_fee_wt)); 1041 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1042 plugin->lookup_wire_transfer (plugin->cls, 1043 &wire_out_wtid, 1044 &cb_wt_never, 1045 NULL)); 1046 1047 { 1048 struct TALER_PrivateContractHashP h_contract_terms_wt2 = 1049 h_contract_terms_wt; 1050 bool pending; 1051 struct TALER_WireTransferIdentifierRawP wtid2; 1052 struct TALER_Amount coin_contribution2; 1053 struct TALER_Amount coin_fee2; 1054 struct GNUNET_TIME_Timestamp execution_time2; 1055 struct TALER_EXCHANGEDB_KycStatus kyc; 1056 union TALER_AccountPublicKeyP account_pub; 1057 1058 h_contract_terms_wt2.hash.bits[0]++; 1059 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1060 plugin->lookup_transfer_by_deposit (plugin->cls, 1061 &h_contract_terms_wt2, 1062 &h_wire_wt, 1063 &coin_pub_wt, 1064 &merchant_pub_wt, 1065 &pending, 1066 &wtid2, 1067 &execution_time2, 1068 &coin_contribution2, 1069 &coin_fee2, 1070 &kyc, 1071 &account_pub)); 1072 } 1073 { 1074 struct TALER_ReservePublicKeyP rpub; 1075 1076 memset (&rpub, 1077 44, 1078 sizeof (rpub)); 1079 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1080 plugin->store_wire_transfer_out (plugin->cls, 1081 wire_out_date, 1082 &wire_out_wtid, 1083 &h_payto, 1084 "my-config-section", 1085 &wire_out_amount)); 1086 } 1087 /* And now the commit should still succeed! */ 1088 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1089 plugin->commit (plugin->cls)); 1090 1091 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1092 plugin->lookup_wire_transfer (plugin->cls, 1093 &wire_out_wtid, 1094 &cb_wt_check, 1095 &cb_wt_never)); 1096 { 1097 bool pending; 1098 struct TALER_WireTransferIdentifierRawP wtid2; 1099 struct TALER_Amount coin_contribution2; 1100 struct TALER_Amount coin_fee2; 1101 struct GNUNET_TIME_Timestamp execution_time2; 1102 struct TALER_EXCHANGEDB_KycStatus kyc; 1103 union TALER_AccountPublicKeyP account_pub; 1104 1105 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1106 plugin->lookup_transfer_by_deposit (plugin->cls, 1107 &h_contract_terms_wt, 1108 &h_wire_wt, 1109 &coin_pub_wt, 1110 &merchant_pub_wt, 1111 &pending, 1112 &wtid2, 1113 &execution_time2, 1114 &coin_contribution2, 1115 &coin_fee2, 1116 &kyc, 1117 &account_pub)); 1118 GNUNET_assert (0 == GNUNET_memcmp (&wtid2, 1119 &wire_out_wtid)); 1120 GNUNET_assert (GNUNET_TIME_timestamp_cmp (execution_time2, 1121 ==, 1122 wire_out_date)); 1123 GNUNET_assert (0 == TALER_amount_cmp (&coin_contribution2, 1124 &coin_value_wt)); 1125 GNUNET_assert (0 == TALER_amount_cmp (&coin_fee2, 1126 &coin_fee_wt)); 1127 } 1128 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1129 plugin->select_wire_out_above_serial_id (plugin->cls, 1130 0, 1131 &audit_wire_cb, 1132 NULL)); 1133 FAILIF (1 != auditor_row_cnt); 1134 1135 return GNUNET_OK; 1136 drop: 1137 return GNUNET_SYSERR; 1138 } 1139 1140 1141 /** 1142 * Function called about recoups the exchange has to perform. 1143 * 1144 * @param cls closure with the expected value for @a coin_blind 1145 * @param rowid row identifier used to uniquely identify the recoup operation 1146 * @param timestamp when did we receive the recoup request 1147 * @param amount how much should be added back to the reserve 1148 * @param reserve_pub public key of the reserve 1149 * @param coin public information about the coin 1150 * @param denom_pub denomination key of @a coin 1151 * @param coin_sig signature with @e coin_pub of type #TALER_SIGNATURE_WALLET_COIN_RECOUP 1152 * @param coin_blind blinding factor used to blind the coin 1153 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 1154 */ 1155 static enum GNUNET_GenericReturnValue 1156 recoup_cb (void *cls, 1157 uint64_t rowid, 1158 struct GNUNET_TIME_Timestamp timestamp, 1159 const struct TALER_Amount *amount, 1160 const struct TALER_ReservePublicKeyP *reserve_pub, 1161 const struct TALER_CoinPublicInfo *coin, 1162 const struct TALER_DenominationPublicKey *denom_pub, 1163 const struct TALER_CoinSpendSignatureP *coin_sig, 1164 const union GNUNET_CRYPTO_BlindingSecretP *coin_blind) 1165 { 1166 const union GNUNET_CRYPTO_BlindingSecretP *cb = cls; 1167 1168 (void) rowid; 1169 (void) timestamp; 1170 (void) amount; 1171 (void) reserve_pub; 1172 (void) coin_sig; 1173 (void) coin; 1174 (void) denom_pub; 1175 FAILIF (NULL == cb); 1176 FAILIF (0 != GNUNET_memcmp (cb, 1177 coin_blind)); 1178 return GNUNET_OK; 1179 drop: 1180 return GNUNET_SYSERR; 1181 } 1182 1183 1184 /** 1185 * Function called on batch deposits that may require a 1186 * wire transfer. 1187 * 1188 * @param cls closure a `struct TALER_EXCHANGEDB_Deposit *` 1189 * @param batch_deposit_serial_id where in the table are we 1190 * @param total_amount value of all missing deposits, including fees 1191 * @param wire_target_h_payto hash of the recipient account's payto URI 1192 * @param deadline what was the earliest requested wire transfer deadline 1193 */ 1194 static void 1195 wire_missing_cb ( 1196 struct TALER_EXCHANGEDB_PostgresContext *pg, 1197 uint64_t batch_deposit_serial_id, 1198 const struct TALER_Amount *total_amount, 1199 const struct TALER_FullPaytoHashP *wire_target_h_payto, 1200 struct GNUNET_TIME_Timestamp deadline) 1201 { 1202 const struct TALER_EXCHANGEDB_CoinDepositInformation *deposit = cls; 1203 1204 (void) batch_deposit_serial_id; 1205 (void) deadline; 1206 (void) wire_target_h_payto; 1207 if (0 == 1208 TALER_amount_cmp (total_amount, 1209 &deposit->amount_with_fee)) 1210 result = 8; 1211 } 1212 1213 1214 /** 1215 * Callback invoked with information about refunds applicable 1216 * to a particular coin. 1217 * 1218 * @param cls closure with the `struct TALER_EXCHANGEDB_Refund *` we expect to get 1219 * @param amount_with_fee amount being refunded 1220 * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop 1221 */ 1222 static enum GNUNET_GenericReturnValue 1223 check_refund_cb (void *cls, 1224 const struct TALER_Amount *amount_with_fee) 1225 { 1226 const struct TALER_EXCHANGEDB_Refund *refund = cls; 1227 1228 if (0 != TALER_amount_cmp (amount_with_fee, 1229 &refund->details.refund_amount)) 1230 { 1231 GNUNET_break (0); 1232 result = 66; 1233 } 1234 return GNUNET_OK; 1235 } 1236 1237 1238 /** 1239 * Information about a melt operation. 1240 */ 1241 struct TALER_EXCHANGEDB_Melt 1242 { 1243 1244 /** 1245 * Overall session data. 1246 */ 1247 struct TALER_EXCHANGEDB_Refresh session; 1248 1249 /** 1250 * Melt fee the exchange charged. 1251 */ 1252 struct TALER_Amount melt_fee; 1253 1254 }; 1255 1256 1257 /** 1258 * Main function that will be run by the scheduler. 1259 * 1260 * @param cls closure with config 1261 */ 1262 static void 1263 run (struct TALER_EXCHANGEDB_PostgresContext *pg) 1264 { 1265 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 1266 struct TALER_CoinSpendSignatureP coin_sig; 1267 struct GNUNET_TIME_Timestamp deadline; 1268 union GNUNET_CRYPTO_BlindingSecretP coin_blind; 1269 struct TALER_ReservePublicKeyP reserve_pub; 1270 struct TALER_ReservePublicKeyP reserve_pub2; 1271 struct TALER_ReservePublicKeyP reserve_pub3; 1272 struct DenomKeyPair *dkp = NULL; 1273 struct TALER_MasterSignatureP master_sig; 1274 struct TALER_EXCHANGEDB_CollectableBlindcoin cbc; 1275 struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL; 1276 struct TALER_EXCHANGEDB_ReserveHistory *rh_head; 1277 struct TALER_EXCHANGEDB_BankTransfer *bt; 1278 struct TALER_EXCHANGEDB_Withdraw withdraw; 1279 struct TALER_HashBlindedPlanchetsP h_planchets; 1280 struct TALER_EXCHANGEDB_CoinDepositInformation deposit; 1281 struct TALER_EXCHANGEDB_BatchDeposit bd; 1282 struct TALER_CoinSpendPublicKeyP cpub2; 1283 struct TALER_MerchantPublicKeyP mpub2; 1284 struct TALER_EXCHANGEDB_Refund refund; 1285 const struct TALER_FullPayto sndr = { 1286 (char *) "payto://x-taler-bank/localhost:8080/1?receiver-name=1" 1287 }; 1288 const struct TALER_FullPayto rcvr = { 1289 (char *) "payto://x-taler-bank/localhost:8080/2?receiver-name=1" 1290 }; 1291 const uint32_t num_partitions = 10; 1292 unsigned int matched; 1293 enum GNUNET_DB_QueryStatus qs; 1294 struct GNUNET_TIME_Timestamp now; 1295 struct TALER_WireSaltP salt; 1296 struct TALER_CoinPubHashP c_hash; 1297 uint64_t known_coin_id; 1298 uint64_t rrc_serial; 1299 struct TALER_EXCHANGEDB_Refresh refresh; 1300 struct TALER_DenominationPublicKey *new_denom_pubs = NULL; 1301 uint64_t withdraw_serial_id; 1302 uint64_t melt_serial_id; 1303 struct TALER_PlanchetMasterSecretP ps; 1304 union GNUNET_CRYPTO_BlindingSecretP bks; 1305 struct TALER_Amount amount_with_fee; 1306 const struct TALER_ExchangeBlindingValues *alg_values 1307 = TALER_denom_ewv_rsa_singleton (); 1308 1309 memset (&deposit, 1310 0, 1311 sizeof (deposit)); 1312 memset (&bd, 1313 0, 1314 sizeof (bd)); 1315 bd.receiver_wire_account = rcvr; 1316 bd.cdis = &deposit; 1317 bd.num_cdis = 1; 1318 memset (&salt, 1319 45, 1320 sizeof (salt)); 1321 memset (&refresh, 1322 0, 1323 sizeof (refresh)); 1324 ZR_BLK (&cbc); 1325 ZR_BLK (&withdraw); 1326 if (NULL == 1327 (plugin = TALER_EXCHANGEDB_plugin_load (cfg, 1328 true))) 1329 { 1330 result = 77; 1331 return; 1332 } 1333 (void) plugin->drop_tables (plugin->cls); 1334 if (GNUNET_OK != 1335 plugin->create_tables (plugin->cls, 1336 true, 1337 num_partitions)) 1338 { 1339 result = 77; 1340 goto cleanup; 1341 } 1342 plugin->preflight (plugin->cls); 1343 FAILIF (GNUNET_OK != 1344 plugin->start (plugin->cls, 1345 "test-1")); 1346 1347 1348 /* test DB is empty */ 1349 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1350 plugin->select_recoup_above_serial_id (plugin->cls, 1351 0, 1352 &recoup_cb, 1353 NULL)); 1354 1355 RND_BLK (&reserve_pub); 1356 GNUNET_assert (GNUNET_OK == 1357 TALER_string_to_amount (CURRENCY ":1.000000", 1358 &global_amount)); 1359 GNUNET_assert (GNUNET_OK == 1360 TALER_string_to_amount (CURRENCY ":1.000010", 1361 &global_value)); 1362 GNUNET_assert (GNUNET_OK == 1363 TALER_string_to_amount (CURRENCY ":0.000010", 1364 &global_fees.withdraw)); 1365 GNUNET_assert (GNUNET_OK == 1366 TALER_string_to_amount (CURRENCY ":0.000010", 1367 &global_fees.deposit)); 1368 GNUNET_assert (GNUNET_OK == 1369 TALER_string_to_amount (CURRENCY ":0.000010", 1370 &global_fees.refresh)); 1371 GNUNET_assert (GNUNET_OK == 1372 TALER_string_to_amount (CURRENCY ":0.000010", 1373 &global_fees.refund)); 1374 GNUNET_assert (GNUNET_OK == 1375 TALER_string_to_amount (CURRENCY ":1.000010", 1376 &amount_with_fee)); 1377 result = 4; 1378 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1379 plugin->commit (plugin->cls)); 1380 now = GNUNET_TIME_timestamp_get (); 1381 { 1382 struct TALER_EXCHANGEDB_ReserveInInfo reserve = { 1383 .reserve_pub = &reserve_pub, 1384 .balance = &global_value, 1385 .execution_time = now, 1386 .sender_account_details = sndr, 1387 .exchange_account_name = "exchange-account-1", 1388 .wire_reference = 4 1389 }; 1390 enum GNUNET_DB_QueryStatus qsr; 1391 1392 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1393 plugin->reserves_in_insert (plugin->cls, 1394 &reserve, 1395 1, 1396 &qsr)); 1397 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1398 qsr); 1399 } 1400 FAILIF (GNUNET_OK != 1401 check_reserve (&reserve_pub, 1402 global_value.value, 1403 global_value.fraction, 1404 global_value.currency)); 1405 now = GNUNET_TIME_timestamp_get (); 1406 RND_BLK (&reserve_pub2); 1407 { 1408 struct TALER_EXCHANGEDB_ReserveInInfo reserve = { 1409 .reserve_pub = &reserve_pub2, 1410 .balance = &global_value, 1411 .execution_time = now, 1412 .sender_account_details = sndr, 1413 .exchange_account_name = "exchange-account-1", 1414 .wire_reference = 5 1415 }; 1416 enum GNUNET_DB_QueryStatus qsr; 1417 1418 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1419 plugin->reserves_in_insert (plugin->cls, 1420 &reserve, 1421 1, 1422 &qsr)); 1423 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1424 qsr); 1425 } 1426 FAILIF (GNUNET_OK != 1427 plugin->start (plugin->cls, 1428 "test-2")); 1429 FAILIF (GNUNET_OK != 1430 check_reserve (&reserve_pub, 1431 global_value.value, 1432 global_value.fraction, 1433 global_value.currency)); 1434 FAILIF (GNUNET_OK != 1435 check_reserve (&reserve_pub2, 1436 global_value.value, 1437 global_value.fraction, 1438 global_value.currency)); 1439 result = 5; 1440 now = GNUNET_TIME_timestamp_get (); 1441 dkp = create_denom_key_pair (RSA_KEY_SIZE, 1442 now, 1443 &global_value, 1444 &global_fees); 1445 GNUNET_assert (NULL != dkp); 1446 TALER_denom_pub_hash (&dkp->pub, 1447 &cbc.denom_pub_hash); 1448 RND_BLK (&cbc.reserve_sig); 1449 RND_BLK (&ps); 1450 TALER_planchet_blinding_secret_create (&ps, 1451 alg_values, 1452 &bks); 1453 { 1454 struct TALER_PlanchetDetail pd; 1455 struct TALER_CoinSpendPublicKeyP coin_pub; 1456 1457 1458 RND_BLK (&coin_pub); 1459 GNUNET_assert (GNUNET_OK == 1460 TALER_denom_blind (&dkp->pub, 1461 &bks, 1462 NULL, 1463 NULL, 1464 &coin_pub, 1465 alg_values, 1466 &c_hash, 1467 &pd.blinded_planchet)); 1468 TALER_coin_ev_hash (&pd.blinded_planchet, 1469 &cbc.denom_pub_hash, 1470 &cbc.h_coin_envelope); 1471 1472 GNUNET_assert ( 1473 GNUNET_OK == 1474 TALER_denom_sign_blinded ( 1475 &cbc.sig, 1476 &dkp->priv, 1477 false, 1478 &pd.blinded_planchet)); 1479 1480 TALER_wallet_blinded_planchets_hash ( 1481 1, 1482 &pd.blinded_planchet, 1483 &cbc.denom_pub_hash, 1484 &h_planchets); 1485 1486 TALER_blinded_planchet_free (&pd.blinded_planchet); 1487 } 1488 1489 cbc.reserve_pub = reserve_pub; 1490 cbc.amount_with_fee = global_value; 1491 GNUNET_assert (GNUNET_OK == 1492 TALER_amount_set_zero (CURRENCY, 1493 &cbc.withdraw_fee)); 1494 1495 { 1496 bool balance_ok; 1497 bool age_ok; 1498 bool idempotent; 1499 uint16_t noreveal_index; 1500 bool nonce_reuse; 1501 uint16_t maximum_age; 1502 uint32_t reserve_birthday; 1503 uint64_t denom_serial = 1; /* bold assumption */ 1504 struct TALER_Amount reserve_balance; 1505 struct TALER_BlindingMasterSeedP blinding_seed = {0}; 1506 struct GNUNET_CRYPTO_CSPublicRPairP cs_r_pubs = {0}; 1507 struct TALER_EXCHANGEDB_Withdraw withdraw_in = { 1508 .amount_with_fee = global_value, 1509 .age_proof_required = true, 1510 .max_age = 0, 1511 .noreveal_index = 42, 1512 .reserve_pub = reserve_pub, 1513 .reserve_sig = cbc.reserve_sig, 1514 .h_planchets = h_planchets, 1515 .no_blinding_seed = false, 1516 .blinding_seed = blinding_seed, 1517 .num_coins = 1, 1518 .h_coin_evs = &cbc.h_coin_envelope, 1519 .denom_sigs = &cbc.sig, 1520 .denom_serials = &denom_serial, 1521 .num_cs_r_pubs = 1, 1522 .cs_r_pubs = &cs_r_pubs, 1523 }; 1524 struct TALER_Amount zero_amount; 1525 1526 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1527 plugin->do_withdraw (plugin->cls, 1528 &withdraw_in, 1529 &now, 1530 &balance_ok, 1531 &reserve_balance, 1532 &age_ok, 1533 &maximum_age, 1534 &reserve_birthday, 1535 &idempotent, 1536 &noreveal_index, 1537 &nonce_reuse)); 1538 GNUNET_assert (! idempotent); 1539 GNUNET_assert (! nonce_reuse); 1540 GNUNET_assert (balance_ok); 1541 1542 1543 /** 1544 * Set the amount in the withdraw to zero, 1545 * to avoid triggering balance_ok issues for 1546 * the conflict and nonce_reuse tests. 1547 */ 1548 GNUNET_assert (GNUNET_OK == 1549 TALER_string_to_amount (CURRENCY ":0.000000", 1550 &zero_amount)); 1551 withdraw_in.amount_with_fee = zero_amount; 1552 1553 /** 1554 * Change some values to trigger conflict 1555 * due to h_planchet, not nonce. 1556 */ 1557 withdraw_in.blinding_seed.key_data[0] = 1; 1558 noreveal_index = -1; 1559 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1560 plugin->do_withdraw (plugin->cls, 1561 &withdraw_in, 1562 &now, 1563 &balance_ok, 1564 &reserve_balance, 1565 &age_ok, 1566 &maximum_age, 1567 &reserve_birthday, 1568 &idempotent, 1569 &noreveal_index, 1570 &nonce_reuse)); 1571 GNUNET_assert (! nonce_reuse); 1572 GNUNET_assert (idempotent); 1573 GNUNET_assert (42 == noreveal_index); 1574 1575 /** 1576 * Make h_planchet unique again, but trigger 1577 * conflict with blinding_seed. 1578 */ 1579 withdraw_in.blinding_seed.key_data[0] = 0; 1580 withdraw_in.h_planchets.hash.bits[0] += 1; 1581 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1582 plugin->do_withdraw (plugin->cls, 1583 &withdraw_in, 1584 &now, 1585 &balance_ok, 1586 &reserve_balance, 1587 &age_ok, 1588 &maximum_age, 1589 &reserve_birthday, 1590 &idempotent, 1591 &noreveal_index, 1592 &nonce_reuse)); 1593 GNUNET_assert (! idempotent); 1594 GNUNET_assert (nonce_reuse); 1595 } 1596 1597 FAILIF (GNUNET_OK != 1598 check_reserve (&reserve_pub, 1599 0, 1600 0, 1601 global_value.currency)); 1602 FAILIF (GNUNET_OK != 1603 check_reserve (&reserve_pub2, 1604 global_value.value, 1605 global_value.fraction, 1606 global_value.currency)); 1607 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1608 plugin->get_reserve_by_h_planchets (plugin->cls, 1609 &h_planchets, 1610 &reserve_pub3, 1611 &withdraw_serial_id)); 1612 FAILIF (0 != GNUNET_memcmp (&reserve_pub, 1613 &reserve_pub3)); 1614 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1615 plugin->get_withdraw (plugin->cls, 1616 &h_planchets, 1617 &withdraw)); 1618 FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_sig, 1619 &cbc.reserve_sig)); 1620 FAILIF (0 != GNUNET_memcmp (&withdraw.reserve_pub, 1621 &cbc.reserve_pub)); 1622 result = 6; 1623 1624 { 1625 struct TALER_DenominationSignature ds; 1626 1627 GNUNET_assert (GNUNET_OK == 1628 TALER_denom_sig_unblind (&ds, 1629 &withdraw.denom_sigs[0], 1630 &bks, 1631 &c_hash, 1632 alg_values, 1633 &dkp->pub)); 1634 FAILIF (GNUNET_OK != 1635 TALER_denom_pub_verify (&dkp->pub, 1636 &ds, 1637 &c_hash)); 1638 TALER_denom_sig_free (&ds); 1639 } 1640 1641 RND_BLK (&coin_sig); 1642 RND_BLK (&coin_blind); 1643 RND_BLK (&deposit.coin.coin_pub); 1644 TALER_denom_pub_hash (&dkp->pub, 1645 &deposit.coin.denom_pub_hash); 1646 GNUNET_assert (GNUNET_OK == 1647 TALER_denom_sig_unblind (&deposit.coin.denom_sig, 1648 &cbc.sig, 1649 &bks, 1650 &c_hash, 1651 alg_values, 1652 &dkp->pub)); 1653 deadline = GNUNET_TIME_timestamp_get (); 1654 { 1655 struct TALER_DenominationHashP dph; 1656 struct TALER_AgeCommitmentHashP agh; 1657 1658 FAILIF (TALER_EXCHANGEDB_CKS_ADDED != 1659 plugin->ensure_coin_known (plugin->cls, 1660 &deposit.coin, 1661 &known_coin_id, 1662 &dph, 1663 &agh)); 1664 } 1665 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1666 plugin->commit (plugin->cls)); 1667 { 1668 struct GNUNET_TIME_Timestamp deposit_timestamp 1669 = GNUNET_TIME_timestamp_get (); 1670 bool balance_ok; 1671 uint32_t bad_balance_idx; 1672 bool in_conflict; 1673 struct TALER_FullPaytoHashP h_payto; 1674 1675 RND_BLK (&h_payto); 1676 bd.refund_deadline 1677 = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS); 1678 bd.wire_deadline 1679 = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_MONTHS); 1680 deposit.amount_with_fee = global_value; 1681 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1682 plugin->do_deposit (plugin->cls, 1683 &bd, 1684 &deposit_timestamp, 1685 &balance_ok, 1686 &bad_balance_idx, 1687 &in_conflict)); 1688 FAILIF (! balance_ok); 1689 FAILIF (in_conflict); 1690 } 1691 1692 { 1693 bool not_found; 1694 bool refund_ok; 1695 bool gone; 1696 bool conflict; 1697 1698 refund.coin = deposit.coin; 1699 refund.details.merchant_pub = bd.merchant_pub; 1700 RND_BLK (&refund.details.merchant_sig); 1701 refund.details.h_contract_terms = bd.h_contract_terms; 1702 refund.details.rtransaction_id = 1; 1703 refund.details.refund_amount = global_value; 1704 refund.details.refund_fee = global_fees.refund; 1705 RND_BLK (&refund.details.merchant_sig); 1706 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1707 plugin->do_refund (plugin->cls, 1708 &refund, 1709 &global_fees.deposit, 1710 known_coin_id, 1711 ¬_found, 1712 &refund_ok, 1713 &gone, 1714 &conflict)); 1715 FAILIF (not_found); 1716 FAILIF (! refund_ok); 1717 FAILIF (gone); 1718 FAILIF (conflict); 1719 1720 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1721 plugin->select_refunds_by_coin (plugin->cls, 1722 &refund.coin.coin_pub, 1723 &refund.details.merchant_pub, 1724 &refund.details.h_contract_terms, 1725 &check_refund_cb, 1726 &refund)); 1727 } 1728 1729 1730 /* test do_refresh */ 1731 #pragma message "add refresh test for new refresh" 1732 #if 0 1733 { 1734 bool zombie_required = false; 1735 bool balance_ok; 1736 bool idempotent; 1737 uint16_t idem_noreveal_index; 1738 struct TALER_Amount insufficient_funds; 1739 struct TALER_EXCHANGEDB_Refresh_v26 refresh_v26; 1740 1741 refresh_v26.coin = deposit.coin; 1742 RND_BLK (&refresh_v26.coin_sig); 1743 RND_BLK (&refresh_v26.rc); 1744 refresh_v26.amount_with_fee = global_value; 1745 refresh_v26.noreveal_index = MELT_NOREVEAL_INDEX; 1746 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1747 plugin->do_refresh (plugin->cls, 1748 &refresh_v26, 1749 NULL, 1750 &idempotent, 1751 &idem_noreveal_index, 1752 &zombie_required, 1753 &balance_ok, 1754 &insufficient_funds)); 1755 FAILIF (! balance_ok); 1756 FAILIF (zombie_required); 1757 } 1758 #endif 1759 1760 1761 /* test do_melt */ 1762 { 1763 bool zombie_required = false; 1764 bool balance_ok; 1765 1766 refresh.coin = deposit.coin; 1767 RND_BLK (&refresh.coin_sig); 1768 RND_BLK (&refresh.rc); 1769 refresh.amount_with_fee = global_value; 1770 refresh.noreveal_index = MELT_NOREVEAL_INDEX; 1771 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1772 plugin->do_melt (plugin->cls, 1773 NULL, 1774 &refresh, 1775 known_coin_id, 1776 &zombie_required, 1777 &balance_ok)); 1778 FAILIF (! balance_ok); 1779 FAILIF (zombie_required); 1780 } 1781 1782 /* test get_melt */ 1783 { 1784 struct TALER_EXCHANGEDB_Melt ret_refresh_session; 1785 1786 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1787 plugin->get_melt (plugin->cls, 1788 &refresh.rc, 1789 &ret_refresh_session, 1790 &melt_serial_id)); 1791 FAILIF (refresh.noreveal_index != 1792 ret_refresh_session.session.noreveal_index); 1793 FAILIF (0 != 1794 TALER_amount_cmp (&refresh.amount_with_fee, 1795 &ret_refresh_session.session.amount_with_fee)); 1796 FAILIF (0 != 1797 TALER_amount_cmp (&global_fees.refresh, 1798 &ret_refresh_session.melt_fee)); 1799 FAILIF (0 != 1800 GNUNET_memcmp (&refresh.rc, 1801 &ret_refresh_session.session.rc)); 1802 FAILIF (0 != GNUNET_memcmp (&refresh.coin_sig, 1803 &ret_refresh_session.session.coin_sig)); 1804 FAILIF (0 != 1805 GNUNET_memcmp (&refresh.coin.coin_pub, 1806 &ret_refresh_session.session.coin.coin_pub)); 1807 FAILIF (0 != 1808 GNUNET_memcmp (&refresh.coin.denom_pub_hash, 1809 &ret_refresh_session.session.coin.denom_pub_hash)); 1810 } 1811 1812 { 1813 /* test 'select_refreshes_above_serial_id' */ 1814 auditor_row_cnt = 0; 1815 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1816 plugin->select_refreshes_above_serial_id (plugin->cls, 1817 0, 1818 &audit_refresh_session_cb, 1819 NULL)); 1820 FAILIF (1 != auditor_row_cnt); 1821 } 1822 1823 /* do refresh-reveal */ 1824 now = GNUNET_TIME_timestamp_get (); 1825 { 1826 new_dkp = GNUNET_new_array (MELT_NEW_COINS, 1827 struct DenomKeyPair *); 1828 new_denom_pubs = GNUNET_new_array (MELT_NEW_COINS, 1829 struct TALER_DenominationPublicKey); 1830 revealed_coins 1831 = GNUNET_new_array (MELT_NEW_COINS, 1832 struct TALER_EXCHANGEDB_RefreshRevealedCoin); 1833 for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) 1834 { 1835 struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin; 1836 struct GNUNET_CRYPTO_BlindedMessage *rp; 1837 struct GNUNET_CRYPTO_RsaBlindedMessage *rsa; 1838 struct TALER_BlindedPlanchet *bp; 1839 1840 new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE, 1841 now, 1842 &global_value, 1843 &global_fees); 1844 GNUNET_assert (NULL != new_dkp[cnt]); 1845 new_denom_pubs[cnt] = new_dkp[cnt]->pub; 1846 ccoin = &revealed_coins[cnt]; 1847 bp = &ccoin->blinded_planchet; 1848 rp = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage); 1849 bp->blinded_message = rp; 1850 rp->cipher = GNUNET_CRYPTO_BSA_RSA; 1851 rp->rc = 1; 1852 rsa = &rp->details.rsa_blinded_message; 1853 rsa->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( 1854 (RSA_KEY_SIZE / 8) - 1); 1855 rsa->blinded_msg = GNUNET_malloc (rsa->blinded_msg_size); 1856 GNUNET_CRYPTO_random_block (rsa->blinded_msg, 1857 rsa->blinded_msg_size); 1858 TALER_denom_pub_hash (&new_dkp[cnt]->pub, 1859 &ccoin->h_denom_pub); 1860 TALER_denom_ewv_copy (&ccoin->exchange_vals, 1861 alg_values); 1862 TALER_coin_ev_hash (bp, 1863 &ccoin->h_denom_pub, 1864 &ccoin->coin_envelope_hash); 1865 GNUNET_assert (GNUNET_OK == 1866 TALER_denom_sign_blinded (&ccoin->coin_sig, 1867 &new_dkp[cnt]->priv, 1868 true, 1869 bp)); 1870 } 1871 RND_BLK (&tprivs); 1872 RND_BLK (&tpub); 1873 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 1874 plugin->get_refresh_reveal (plugin->cls, 1875 &refresh.rc, 1876 &never_called_cb, 1877 NULL)); 1878 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1879 plugin->insert_refresh_reveal (plugin->cls, 1880 melt_serial_id, 1881 MELT_NEW_COINS, 1882 revealed_coins, 1883 TALER_CNC_KAPPA - 1, 1884 tprivs, 1885 &tpub)); 1886 { 1887 struct TALER_BlindedCoinHashP h_coin_ev; 1888 struct TALER_CoinSpendPublicKeyP ocp; 1889 struct TALER_DenominationHashP denom_hash; 1890 1891 TALER_denom_pub_hash (&new_denom_pubs[0], 1892 &denom_hash); 1893 TALER_coin_ev_hash (&revealed_coins[0].blinded_planchet, 1894 &denom_hash, 1895 &h_coin_ev); 1896 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1897 plugin->get_old_coin_by_h_blind (plugin->cls, 1898 &h_coin_ev, 1899 &ocp, 1900 &rrc_serial)); 1901 FAILIF (0 != 1902 GNUNET_memcmp (&ocp, 1903 &refresh.coin.coin_pub)); 1904 } 1905 FAILIF (0 >= 1906 plugin->get_refresh_reveal (plugin->cls, 1907 &refresh.rc, 1908 &check_refresh_reveal_cb, 1909 NULL)); 1910 qs = plugin->get_link_data (plugin->cls, 1911 &refresh.coin.coin_pub, 1912 &handle_link_data_cb, 1913 NULL); 1914 FAILIF (0 >= qs); 1915 { 1916 /* Just to test fetching a coin with melt history */ 1917 struct TALER_EXCHANGEDB_TransactionList *tl; 1918 uint64_t etag; 1919 struct TALER_Amount balance; 1920 struct TALER_DenominationHashP h_denom_pub; 1921 1922 qs = plugin->get_coin_transactions (plugin->cls, 1923 true, 1924 &refresh.coin.coin_pub, 1925 0, 1926 0, 1927 &etag, 1928 &balance, 1929 &h_denom_pub, 1930 &tl); 1931 FAILIF (0 >= qs); 1932 FAILIF (NULL == tl); 1933 plugin->free_coin_transaction_list (plugin->cls, 1934 tl); 1935 } 1936 } 1937 1938 /* do recoup-refresh */ 1939 { 1940 struct GNUNET_TIME_Timestamp recoup_timestamp 1941 = GNUNET_TIME_timestamp_get (); 1942 union GNUNET_CRYPTO_BlindingSecretP coin_bks; 1943 uint64_t new_known_coin_id; 1944 struct TALER_CoinPublicInfo new_coin; 1945 struct TALER_DenominationHashP dph; 1946 struct TALER_AgeCommitmentHashP agh; 1947 bool recoup_ok; 1948 bool internal_failure; 1949 1950 new_coin = deposit.coin; /* steal basic data */ 1951 RND_BLK (&new_coin.coin_pub); 1952 FAILIF (TALER_EXCHANGEDB_CKS_ADDED != 1953 plugin->ensure_coin_known (plugin->cls, 1954 &new_coin, 1955 &new_known_coin_id, 1956 &dph, 1957 &agh)); 1958 RND_BLK (&coin_bks); 1959 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1960 plugin->do_recoup_refresh (plugin->cls, 1961 &deposit.coin.coin_pub, 1962 rrc_serial, 1963 &coin_bks, 1964 &new_coin.coin_pub, 1965 new_known_coin_id, 1966 &coin_sig, 1967 &recoup_timestamp, 1968 &recoup_ok, 1969 &internal_failure)); 1970 FAILIF (! recoup_ok); 1971 FAILIF (internal_failure); 1972 } 1973 1974 /* do recoup */ 1975 { 1976 struct TALER_EXCHANGEDB_Reserve pre_reserve; 1977 struct TALER_EXCHANGEDB_Reserve post_reserve; 1978 struct TALER_Amount delta; 1979 bool recoup_ok; 1980 bool internal_failure; 1981 struct GNUNET_TIME_Timestamp recoup_timestamp 1982 = GNUNET_TIME_timestamp_get (); 1983 1984 pre_reserve.pub = reserve_pub; 1985 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1986 plugin->reserves_get (plugin->cls, 1987 &pre_reserve)); 1988 FAILIF (! TALER_amount_is_zero (&pre_reserve.balance)); 1989 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1990 plugin->do_recoup (plugin->cls, 1991 &reserve_pub, 1992 withdraw_serial_id, 1993 &coin_blind, 1994 &deposit.coin.coin_pub, 1995 known_coin_id, 1996 &coin_sig, 1997 &recoup_timestamp, 1998 &recoup_ok, 1999 &internal_failure)); 2000 FAILIF (internal_failure); 2001 FAILIF (! recoup_ok); 2002 post_reserve.pub = reserve_pub; 2003 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2004 plugin->reserves_get (plugin->cls, 2005 &post_reserve)); 2006 FAILIF (0 >= 2007 TALER_amount_subtract (&delta, 2008 &post_reserve.balance, 2009 &pre_reserve.balance)); 2010 FAILIF (0 != 2011 TALER_amount_cmp (&delta, 2012 &global_value)); 2013 } 2014 2015 FAILIF (GNUNET_OK != 2016 plugin->start (plugin->cls, 2017 "test-3")); 2018 2019 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2020 plugin->select_recoup_above_serial_id (plugin->cls, 2021 0, 2022 &recoup_cb, 2023 &coin_blind)); 2024 /* Do reserve close */ 2025 now = GNUNET_TIME_timestamp_get (); 2026 GNUNET_assert (GNUNET_OK == 2027 TALER_string_to_amount (CURRENCY ":0.000010", 2028 &fee_closing)); 2029 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2030 plugin->insert_reserve_closed (plugin->cls, 2031 &reserve_pub2, 2032 now, 2033 sndr, 2034 &wire_out_wtid, 2035 &amount_with_fee, 2036 &fee_closing, 2037 0)); 2038 FAILIF (GNUNET_OK != 2039 check_reserve (&reserve_pub2, 2040 0, 2041 0, 2042 global_value.currency)); 2043 now = GNUNET_TIME_timestamp_get (); 2044 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2045 plugin->insert_reserve_closed (plugin->cls, 2046 &reserve_pub, 2047 now, 2048 sndr, 2049 &wire_out_wtid, 2050 &global_value, 2051 &fee_closing, 2052 0)); 2053 FAILIF (GNUNET_OK != 2054 check_reserve (&reserve_pub, 2055 0, 2056 0, 2057 global_value.currency)); 2058 result = 7; 2059 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2060 plugin->commit (plugin->cls)); 2061 2062 2063 /* check reserve history */ 2064 { 2065 struct TALER_Amount balance; 2066 uint64_t etag_out; 2067 2068 qs = plugin->get_reserve_history (plugin->cls, 2069 &reserve_pub, 2070 0, 2071 0, 2072 &etag_out, 2073 &balance, 2074 &rh); 2075 } 2076 FAILIF (0 > qs); 2077 FAILIF (NULL == rh); 2078 rh_head = rh; 2079 { 2080 unsigned int cnt; 2081 2082 for (cnt = 0; 2083 NULL != rh_head; 2084 rh_head = rh_head->next, cnt++) 2085 { 2086 switch (rh_head->type) 2087 { 2088 case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE: 2089 bt = rh_head->details.bank; 2090 FAILIF (0 != 2091 GNUNET_memcmp (&bt->reserve_pub, 2092 &reserve_pub)); 2093 /* this is the amount we transferred twice*/ 2094 FAILIF (1 != bt->amount.value); 2095 FAILIF (1000 != bt->amount.fraction); 2096 FAILIF (0 != strcmp (CURRENCY, 2097 bt->amount.currency)); 2098 FAILIF (NULL == bt->sender_account_details.full_payto); 2099 break; 2100 case TALER_EXCHANGEDB_RO_WITHDRAW_COINS: 2101 { 2102 struct TALER_EXCHANGEDB_Withdraw *rh_withdraw = 2103 rh_head->details.withdraw; 2104 FAILIF (0 != 2105 GNUNET_memcmp (&rh_withdraw->reserve_pub, 2106 &reserve_pub)); 2107 #pragma message "maybe more tests!?" 2108 } 2109 break; 2110 case TALER_EXCHANGEDB_RO_RECOUP_COIN: 2111 { 2112 struct TALER_EXCHANGEDB_Recoup *recoup = rh_head->details.recoup; 2113 2114 FAILIF (0 != 2115 GNUNET_memcmp (&recoup->coin_sig, 2116 &coin_sig)); 2117 FAILIF (0 != 2118 GNUNET_memcmp (&recoup->coin_blind, 2119 &coin_blind)); 2120 FAILIF (0 != 2121 GNUNET_memcmp (&recoup->reserve_pub, 2122 &reserve_pub)); 2123 FAILIF (0 != 2124 GNUNET_memcmp (&recoup->coin.coin_pub, 2125 &deposit.coin.coin_pub)); 2126 FAILIF (0 != 2127 TALER_amount_cmp (&recoup->value, 2128 &global_value)); 2129 } 2130 break; 2131 case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK: 2132 { 2133 struct TALER_EXCHANGEDB_ClosingTransfer *closing 2134 = rh_head->details.closing; 2135 2136 FAILIF (0 != 2137 GNUNET_memcmp (&closing->reserve_pub, 2138 &reserve_pub)); 2139 FAILIF (0 != TALER_amount_cmp (&closing->amount, 2140 &amount_with_fee)); 2141 FAILIF (0 != TALER_amount_cmp (&closing->closing_fee, 2142 &fee_closing)); 2143 } 2144 break; 2145 case TALER_EXCHANGEDB_RO_PURSE_MERGE: 2146 { 2147 /* FIXME: not yet tested */ 2148 break; 2149 } 2150 case TALER_EXCHANGEDB_RO_HISTORY_REQUEST: 2151 { 2152 /* FIXME: not yet tested */ 2153 break; 2154 } 2155 case TALER_EXCHANGEDB_RO_OPEN_REQUEST: 2156 { 2157 /* FIXME: not yet tested */ 2158 break; 2159 } 2160 case TALER_EXCHANGEDB_RO_CLOSE_REQUEST: 2161 { 2162 /* FIXME: not yet tested */ 2163 break; 2164 } 2165 } 2166 } 2167 GNUNET_assert (4 == cnt); 2168 FAILIF (4 != cnt); 2169 } 2170 2171 auditor_row_cnt = 0; 2172 FAILIF (0 >= 2173 plugin->select_reserves_in_above_serial_id (plugin->cls, 2174 0, 2175 &audit_reserve_in_cb, 2176 NULL)); 2177 FAILIF (0 >= 2178 plugin->select_withdrawals_above_serial_id (plugin->cls, 2179 0, 2180 &audit_reserve_out_cb, 2181 NULL)); 2182 FAILIF (3 != auditor_row_cnt); 2183 2184 2185 auditor_row_cnt = 0; 2186 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2187 plugin->select_refunds_above_serial_id (plugin->cls, 2188 0, 2189 &audit_refund_cb, 2190 NULL)); 2191 FAILIF (1 != auditor_row_cnt); 2192 { 2193 uint64_t etag = 0; 2194 struct TALER_Amount balance; 2195 struct TALER_DenominationHashP h_denom_pub; 2196 struct TALER_EXCHANGEDB_TransactionList *tl; 2197 2198 qs = plugin->get_coin_transactions (plugin->cls, 2199 true, 2200 &refund.coin.coin_pub, 2201 0, 2202 0, 2203 &etag, 2204 &balance, 2205 &h_denom_pub, 2206 &tl); 2207 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs); 2208 GNUNET_assert (NULL != tl); 2209 matched = 0; 2210 for (struct TALER_EXCHANGEDB_TransactionList *tlp = tl; 2211 NULL != tlp; 2212 tlp = tlp->next) 2213 { 2214 switch (tlp->type) 2215 { 2216 case TALER_EXCHANGEDB_TT_DEPOSIT: 2217 { 2218 struct TALER_EXCHANGEDB_DepositListEntry *have = tlp->details.deposit; 2219 2220 /* Note: we're not comparing the denomination keys, as there is 2221 still the question of whether we should even bother exporting 2222 them here. */ 2223 FAILIF (0 != 2224 GNUNET_memcmp (&have->csig, 2225 &deposit.csig)); 2226 FAILIF (0 != 2227 GNUNET_memcmp (&have->merchant_pub, 2228 &bd.merchant_pub)); 2229 FAILIF (0 != 2230 GNUNET_memcmp (&have->h_contract_terms, 2231 &bd.h_contract_terms)); 2232 FAILIF (0 != 2233 GNUNET_memcmp (&have->wire_salt, 2234 &bd.wire_salt)); 2235 FAILIF (GNUNET_TIME_timestamp_cmp (have->timestamp, 2236 !=, 2237 bd.wallet_timestamp)); 2238 FAILIF (GNUNET_TIME_timestamp_cmp (have->refund_deadline, 2239 !=, 2240 bd.refund_deadline)); 2241 FAILIF (GNUNET_TIME_timestamp_cmp (have->wire_deadline, 2242 !=, 2243 bd.wire_deadline)); 2244 FAILIF (0 != TALER_amount_cmp (&have->amount_with_fee, 2245 &deposit.amount_with_fee)); 2246 matched |= 1; 2247 break; 2248 } 2249 /* this coin pub was actually never melted... */ 2250 case TALER_EXCHANGEDB_TT_MELT: 2251 FAILIF (0 != 2252 GNUNET_memcmp (&refresh.rc, 2253 &tlp->details.melt->rc)); 2254 matched |= 2; 2255 break; 2256 case TALER_EXCHANGEDB_TT_REFUND: 2257 { 2258 struct TALER_EXCHANGEDB_RefundListEntry *have = tlp->details.refund; 2259 2260 /* Note: we're not comparing the denomination keys, as there is 2261 still the question of whether we should even bother exporting 2262 them here. */ 2263 FAILIF (0 != GNUNET_memcmp (&have->merchant_pub, 2264 &refund.details.merchant_pub)); 2265 FAILIF (0 != GNUNET_memcmp (&have->merchant_sig, 2266 &refund.details.merchant_sig)); 2267 FAILIF (0 != GNUNET_memcmp (&have->h_contract_terms, 2268 &refund.details.h_contract_terms)); 2269 FAILIF (have->rtransaction_id != refund.details.rtransaction_id); 2270 FAILIF (0 != TALER_amount_cmp (&have->refund_amount, 2271 &refund.details.refund_amount)); 2272 FAILIF (0 != TALER_amount_cmp (&have->refund_fee, 2273 &refund.details.refund_fee)); 2274 matched |= 4; 2275 break; 2276 } 2277 case TALER_EXCHANGEDB_TT_RECOUP: 2278 { 2279 struct TALER_EXCHANGEDB_RecoupListEntry *recoup = 2280 tlp->details.recoup; 2281 2282 FAILIF (0 != GNUNET_memcmp (&recoup->coin_sig, 2283 &coin_sig)); 2284 FAILIF (0 != GNUNET_memcmp (&recoup->coin_blind, 2285 &coin_blind)); 2286 FAILIF (0 != GNUNET_memcmp (&recoup->reserve_pub, 2287 &reserve_pub)); 2288 FAILIF (0 != TALER_amount_cmp (&recoup->value, 2289 &global_value)); 2290 matched |= 8; 2291 break; 2292 } 2293 case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP: 2294 /* FIXME: check fields better... */ 2295 #pragma \ 2296 message "TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP case doesn't work right now" 2297 matched |= 16; 2298 break; 2299 default: 2300 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2301 "Unexpected coin history transaction type: %d\n", 2302 tlp->type); 2303 FAILIF (1); 2304 break; 2305 } 2306 } 2307 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2308 "matched=%d, SKIPPING FAILIF(31 != matched) FOR NOW\n", 2309 matched); 2310 #pragma message "skipping FAILIF(31 != matched) check for now" 2311 #if 0 2312 FAILIF (31 != matched); 2313 #endif 2314 2315 plugin->free_coin_transaction_list (plugin->cls, 2316 tl); 2317 } 2318 2319 /* Tests for deposits+wire */ 2320 TALER_denom_sig_free (&deposit.coin.denom_sig); 2321 memset (&deposit, 2322 0, 2323 sizeof (deposit)); 2324 RND_BLK (&deposit.coin.coin_pub); 2325 TALER_denom_pub_hash (&dkp->pub, 2326 &deposit.coin.denom_pub_hash); 2327 GNUNET_assert (GNUNET_OK == 2328 TALER_denom_sig_unblind (&deposit.coin.denom_sig, 2329 &cbc.sig, 2330 &bks, 2331 &c_hash, 2332 alg_values, 2333 &dkp->pub)); 2334 RND_BLK (&deposit.csig); 2335 RND_BLK (&bd.merchant_pub); 2336 RND_BLK (&bd.h_contract_terms); 2337 RND_BLK (&bd.wire_salt); 2338 bd.receiver_wire_account.full_payto = 2339 (char *) "payto://iban/DE67830654080004822650?receiver-name=Test"; 2340 TALER_merchant_wire_signature_hash ( 2341 bd.receiver_wire_account, 2342 &bd.wire_salt, 2343 &h_wire_wt); 2344 deposit.amount_with_fee = global_value; 2345 bd.refund_deadline = deadline; 2346 bd.wire_deadline = deadline; 2347 result = 8; 2348 FAILIF (GNUNET_OK != 2349 plugin->start (plugin->cls, 2350 "test-3")); 2351 { 2352 uint64_t known_coin_id2; 2353 struct TALER_DenominationHashP dph; 2354 struct TALER_AgeCommitmentHashP agh; 2355 2356 FAILIF (TALER_EXCHANGEDB_CKS_ADDED != 2357 plugin->ensure_coin_known (plugin->cls, 2358 &deposit.coin, 2359 &known_coin_id2, 2360 &dph, 2361 &agh)); 2362 } 2363 now = GNUNET_TIME_timestamp_get (); 2364 { 2365 struct GNUNET_TIME_Timestamp r; 2366 struct TALER_Amount deposit_fee; 2367 struct TALER_MerchantWireHashP h_wire; 2368 bool balance_ok; 2369 uint32_t bad_idx; 2370 bool ctr_conflict; 2371 2372 TALER_full_payto_hash (bd.receiver_wire_account, 2373 &bd.wire_target_h_payto); 2374 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2375 plugin->do_deposit (plugin->cls, 2376 &bd, 2377 &now, 2378 &balance_ok, 2379 &bad_idx, 2380 &ctr_conflict)); 2381 TALER_merchant_wire_signature_hash (bd.receiver_wire_account, 2382 &bd.wire_salt, 2383 &h_wire); 2384 FAILIF (1 != 2385 plugin->have_deposit2 (plugin->cls, 2386 &bd.h_contract_terms, 2387 &h_wire, 2388 &deposit.coin.coin_pub, 2389 &bd.merchant_pub, 2390 bd.refund_deadline, 2391 &deposit_fee, 2392 &r)); 2393 FAILIF (GNUNET_TIME_timestamp_cmp (now, 2394 !=, 2395 r)); 2396 } 2397 { 2398 result = 66; 2399 FAILIF (0 >= 2400 plugin->select_batch_deposits_missing_wire (plugin->cls, 2401 0, 2402 &wire_missing_cb, 2403 &deposit)); 2404 FAILIF (8 != result); 2405 } 2406 auditor_row_cnt = 0; 2407 FAILIF (0 >= 2408 plugin->select_coin_deposits_above_serial_id (plugin->cls, 2409 0, 2410 &audit_deposit_cb, 2411 NULL)); 2412 FAILIF (0 == auditor_row_cnt); 2413 result = 8; 2414 sleep (2); /* give deposit time to be ready */ 2415 { 2416 struct TALER_MerchantPublicKeyP merchant_pub2; 2417 struct TALER_FullPayto payto_uri2; 2418 2419 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2420 plugin->get_ready_deposit (plugin->cls, 2421 0, 2422 INT32_MAX, 2423 &merchant_pub2, 2424 &payto_uri2)); 2425 FAILIF (0 != GNUNET_memcmp (&merchant_pub2, 2426 &bd.merchant_pub)); 2427 FAILIF (0 != TALER_full_payto_cmp (payto_uri2, 2428 bd.receiver_wire_account)); 2429 TALER_full_payto_hash (payto_uri2, 2430 &global_wire_target_h_payto); 2431 GNUNET_free (payto_uri2.full_payto); 2432 } 2433 2434 { 2435 struct TALER_Amount total; 2436 struct TALER_WireTransferIdentifierRawP wtid; 2437 2438 memset (&wtid, 2439 41, 2440 sizeof (wtid)); 2441 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2442 plugin->aggregate (plugin->cls, 2443 &global_wire_target_h_payto, 2444 &bd.merchant_pub, 2445 &wtid, 2446 &total)); 2447 } 2448 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2449 plugin->commit (plugin->cls)); 2450 FAILIF (GNUNET_OK != 2451 plugin->start (plugin->cls, 2452 "test-3")); 2453 { 2454 struct TALER_WireTransferIdentifierRawP wtid; 2455 struct TALER_Amount total; 2456 struct TALER_WireTransferIdentifierRawP wtid2; 2457 struct TALER_Amount total2; 2458 2459 memset (&wtid, 2460 42, 2461 sizeof (wtid)); 2462 GNUNET_assert (GNUNET_OK == 2463 TALER_string_to_amount (CURRENCY ":42", 2464 &total)); 2465 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2466 plugin->select_aggregation_transient ( 2467 plugin->cls, 2468 &global_wire_target_h_payto, 2469 &bd.merchant_pub, 2470 "x-bank", 2471 &wtid2, 2472 &total2)); 2473 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2474 plugin->create_aggregation_transient ( 2475 plugin->cls, 2476 &global_wire_target_h_payto, 2477 "x-bank", 2478 &bd.merchant_pub, 2479 &wtid, 2480 0, 2481 &total)); 2482 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2483 plugin->select_aggregation_transient ( 2484 plugin->cls, 2485 &global_wire_target_h_payto, 2486 &bd.merchant_pub, 2487 "x-bank", 2488 &wtid2, 2489 &total2)); 2490 FAILIF (0 != 2491 GNUNET_memcmp (&wtid2, 2492 &wtid)); 2493 FAILIF (0 != 2494 TALER_amount_cmp (&total2, 2495 &total)); 2496 GNUNET_assert (GNUNET_OK == 2497 TALER_string_to_amount (CURRENCY ":43", 2498 &total)); 2499 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2500 plugin->update_aggregation_transient ( 2501 plugin->cls, 2502 &global_wire_target_h_payto, 2503 &wtid, 2504 0, 2505 &total)); 2506 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2507 plugin->select_aggregation_transient ( 2508 plugin->cls, 2509 &global_wire_target_h_payto, 2510 &bd.merchant_pub, 2511 "x-bank", 2512 &wtid2, 2513 &total2)); 2514 FAILIF (0 != 2515 GNUNET_memcmp (&wtid2, 2516 &wtid)); 2517 FAILIF (0 != 2518 TALER_amount_cmp (&total2, 2519 &total)); 2520 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2521 plugin->delete_aggregation_transient ( 2522 plugin->cls, 2523 &global_wire_target_h_payto, 2524 &wtid)); 2525 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2526 plugin->select_aggregation_transient ( 2527 plugin->cls, 2528 &global_wire_target_h_payto, 2529 &bd.merchant_pub, 2530 "x-bank", 2531 &wtid2, 2532 &total2)); 2533 } 2534 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2535 plugin->commit (plugin->cls)); 2536 2537 result = 10; 2538 FAILIF (GNUNET_OK != 2539 plugin->start (plugin->cls, 2540 "test-2")); 2541 RND_BLK (&mpub2); /* should fail if merchant is different */ 2542 { 2543 struct TALER_MerchantWireHashP h_wire; 2544 struct GNUNET_TIME_Timestamp r; 2545 struct TALER_Amount deposit_fee; 2546 2547 TALER_merchant_wire_signature_hash (bd.receiver_wire_account, 2548 &bd.wire_salt, 2549 &h_wire); 2550 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2551 plugin->have_deposit2 (plugin->cls, 2552 &bd.h_contract_terms, 2553 &h_wire, 2554 &deposit.coin.coin_pub, 2555 &mpub2, 2556 bd.refund_deadline, 2557 &deposit_fee, 2558 &r)); 2559 RND_BLK (&cpub2); /* should fail if coin is different */ 2560 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2561 plugin->have_deposit2 (plugin->cls, 2562 &bd.h_contract_terms, 2563 &h_wire, 2564 &cpub2, 2565 &bd.merchant_pub, 2566 bd.refund_deadline, 2567 &deposit_fee, 2568 &r)); 2569 } 2570 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2571 plugin->commit (plugin->cls)); 2572 2573 2574 /* test revocation */ 2575 FAILIF (GNUNET_OK != 2576 plugin->start (plugin->cls, 2577 "test-3b")); 2578 RND_BLK (&master_sig); 2579 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2580 plugin->insert_denomination_revocation (plugin->cls, 2581 &cbc.denom_pub_hash, 2582 &master_sig)); 2583 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2584 plugin->commit (plugin->cls)); 2585 plugin->preflight (plugin->cls); 2586 FAILIF (GNUNET_OK != 2587 plugin->start (plugin->cls, 2588 "test-4")); 2589 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 2590 plugin->insert_denomination_revocation (plugin->cls, 2591 &cbc.denom_pub_hash, 2592 &master_sig)); 2593 plugin->rollback (plugin->cls); 2594 plugin->preflight (plugin->cls); 2595 FAILIF (GNUNET_OK != 2596 plugin->start (plugin->cls, 2597 "test-5")); 2598 { 2599 struct TALER_MasterSignatureP msig; 2600 uint64_t rev_rowid; 2601 2602 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 2603 plugin->get_denomination_revocation (plugin->cls, 2604 &cbc.denom_pub_hash, 2605 &msig, 2606 &rev_rowid)); 2607 FAILIF (0 != GNUNET_memcmp (&msig, 2608 &master_sig)); 2609 } 2610 2611 2612 plugin->rollback (plugin->cls); 2613 FAILIF (GNUNET_OK != 2614 test_wire_prepare ()); 2615 FAILIF (GNUNET_OK != 2616 test_wire_out (&bd)); 2617 FAILIF (GNUNET_OK != 2618 test_gc ()); 2619 FAILIF (GNUNET_OK != 2620 test_wire_fees ()); 2621 2622 plugin->preflight (plugin->cls); 2623 2624 result = 0; 2625 2626 drop: 2627 if (0 != result) 2628 plugin->rollback (plugin->cls); 2629 if (NULL != rh) 2630 plugin->free_reserve_history (plugin->cls, 2631 rh); 2632 rh = NULL; 2633 GNUNET_break (GNUNET_OK == 2634 plugin->drop_tables (plugin->cls)); 2635 cleanup: 2636 if (NULL != dkp) 2637 destroy_denom_key_pair (dkp); 2638 if (NULL != revealed_coins) 2639 { 2640 for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++) 2641 { 2642 TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig); 2643 TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet); 2644 } 2645 GNUNET_free (revealed_coins); 2646 revealed_coins = NULL; 2647 } 2648 GNUNET_free (new_denom_pubs); 2649 for (unsigned int cnt = 0; 2650 (NULL != new_dkp) && (cnt < MELT_NEW_COINS) && (NULL != new_dkp[cnt]); 2651 cnt++) 2652 destroy_denom_key_pair (new_dkp[cnt]); 2653 GNUNET_free (new_dkp); 2654 TALER_denom_sig_free (&deposit.coin.denom_sig); 2655 TALER_blinded_denom_sig_free (&cbc.sig); 2656 TALER_blinded_denom_sig_free (withdraw.denom_sigs); 2657 dkp = NULL; 2658 TALER_EXCHANGEDB_plugin_unload (plugin); 2659 plugin = NULL; 2660 } 2661 2662 2663 int 2664 main (int argc, 2665 char *const argv[]) 2666 { 2667 const char *plugin_name; 2668 char *config_filename; 2669 char *testname; 2670 struct GNUNET_CONFIGURATION_Handle *cfg; 2671 2672 (void) argc; 2673 result = -1; 2674 if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) 2675 { 2676 GNUNET_break (0); 2677 return -1; 2678 } 2679 GNUNET_log_setup (argv[0], 2680 "INFO", 2681 NULL); 2682 plugin_name++; 2683 (void) GNUNET_asprintf (&testname, 2684 "test-exchange-db-%s", 2685 plugin_name); 2686 (void) GNUNET_asprintf (&config_filename, 2687 "%s.conf", 2688 testname); 2689 cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ()); 2690 if (GNUNET_OK != 2691 GNUNET_CONFIGURATION_parse (cfg, 2692 config_filename)) 2693 { 2694 GNUNET_break (0); 2695 GNUNET_free (config_filename); 2696 GNUNET_free (testname); 2697 return 2; 2698 } 2699 GNUNET_SCHEDULER_run (&run, 2700 cfg); 2701 GNUNET_CONFIGURATION_destroy (cfg); 2702 GNUNET_free (config_filename); 2703 GNUNET_free (testname); 2704 return result; 2705 } 2706 2707 2708 /* end of test_exchangedb.c */