taler-auditor-sync.c (29199B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-2022 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 taler-auditor-sync.c 18 * @brief Tool used by the auditor to make a 'safe' copy of the exchanges' database. 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include "exchangedb_lib.h" 23 #include "exchange-database/preflight.h" 24 #include "exchange-database/test_aml_officer.h" 25 #include "exchange-database/abort_shard.h" 26 #include "exchange-database/activate_signing_key.h" 27 #include "exchange-database/add_denomination_key.h" 28 #include "exchange-database/add_policy_fulfillment_proof.h" 29 #include "exchange-database/aggregate.h" 30 #include "exchange-database/batch_ensure_coin_known.h" 31 #include "exchange-database/begin_revolving_shard.h" 32 #include "exchange-database/begin_shard.h" 33 #include "exchange-database/clear_aml_lock.h" 34 #include "exchange-database/commit.h" 35 #include "exchange-database/complete_shard.h" 36 #include "exchange-database/compute_shard.h" 37 #include "exchange-database/count_known_coins.h" 38 #include "exchange-database/create_aggregation_transient.h" 39 #include "exchange-database/create_tables.h" 40 #include "exchange-database/delete_aggregation_transient.h" 41 #include "exchange-database/delete_shard_locks.h" 42 #include "exchange-database/disable_rules.h" 43 #include "exchange-database/do_check_deposit_idempotent.h" 44 #include "exchange-database/do_deposit.h" 45 #include "exchange-database/do_purse_delete.h" 46 #include "exchange-database/do_purse_deposit.h" 47 #include "exchange-database/do_purse_merge.h" 48 #include "exchange-database/do_recoup.h" 49 #include "exchange-database/do_recoup_refresh.h" 50 #include "exchange-database/do_refresh.h" 51 #include "exchange-database/do_refund.h" 52 #include "exchange-database/do_reserve_open.h" 53 #include "exchange-database/do_reserve_purse.h" 54 #include "exchange-database/do_withdraw.h" 55 #include "exchange-database/drain_kyc_alert.h" 56 #include "exchange-database/drop_tables.h" 57 #include "exchange-database/enable_rules.h" 58 #include "exchange-database/ensure_coin_known.h" 59 #include "exchange-database/event_listen_cancel.h" 60 #include "exchange-database/event_listen.h" 61 #include "exchange-database/expire_purse.h" 62 #include "exchange-database/find_aggregation_transient.h" 63 #include "exchange-database/gc.h" 64 #include "exchange-database/get_coin_denomination.h" 65 #include "exchange-database/get_coin_transactions.h" 66 #include "exchange-database/get_denomination_by_serial.h" 67 #include "exchange-database/get_denomination_info.h" 68 #include "exchange-database/get_denomination_revocation.h" 69 #include "exchange-database/get_drain_profit.h" 70 #include "exchange-database/get_expired_reserves.h" 71 #include "exchange-database/get_extension_manifest.h" 72 #include "exchange-database/get_global_fee.h" 73 #include "exchange-database/get_global_fees.h" 74 #include "exchange-database/get_known_coin.h" 75 #include "exchange-database/get_kyc_rules.h" 76 #include "exchange-database/get_old_coin_by_h_blind.h" 77 #include "exchange-database/get_pending_kyc_requirement_process.h" 78 #include "exchange-database/get_policy_details.h" 79 #include "exchange-database/get_purse_deposit.h" 80 #include "exchange-database/get_purse_request.h" 81 #include "exchange-database/get_ready_deposit.h" 82 #include "exchange-database/get_refresh.h" 83 #include "exchange-database/get_reserve_balance.h" 84 #include "exchange-database/get_reserve_by_h_planchets.h" 85 #include "exchange-database/get_reserve_history.h" 86 #include "exchange-database/get_signature_for_known_coin.h" 87 #include "exchange-database/get_unfinished_close_requests.h" 88 #include "exchange-database/get_wire_accounts.h" 89 #include "exchange-database/get_wire_fee.h" 90 #include "exchange-database/get_wire_fees.h" 91 #include "exchange-database/get_wire_hash_for_contract.h" 92 #include "exchange-database/get_withdraw.h" 93 #include "exchange-database/have_deposit2.h" 94 #include "exchange-database/inject_auditor_triggers.h" 95 #include "exchange-database/insert_active_legitimization_measure.h" 96 #include "exchange-database/insert_aml_decision.h" 97 #include "exchange-database/insert_aml_officer.h" 98 #include "exchange-database/insert_aml_program_failure.h" 99 #include "exchange-database/insert_auditor_denom_sig.h" 100 #include "exchange-database/insert_auditor.h" 101 #include "exchange-database/insert_close_request.h" 102 #include "exchange-database/insert_contract.h" 103 #include "exchange-database/insert_denomination_info.h" 104 #include "exchange-database/insert_denomination_revocation.h" 105 #include "exchange-database/insert_drain_profit.h" 106 #include "exchange-database/insert_global_fee.h" 107 #include "exchange-database/insert_kyc_failure.h" 108 #include "exchange-database/insert_kyc_requirement_process.h" 109 #include "exchange-database/insert_partner.h" 110 #include "exchange-database/insert_purse_request.h" 111 #include "exchange-database/insert_records_by_table.h" 112 #include "exchange-database/insert_reserve_closed.h" 113 #include "exchange-database/insert_reserve_open_deposit.h" 114 #include "exchange-database/insert_sanction_list_hit.h" 115 #include "exchange-database/insert_signkey_revocation.h" 116 #include "exchange-database/insert_successor_measure.h" 117 #include "exchange-database/insert_wire_fee.h" 118 #include "exchange-database/insert_wire.h" 119 #include "exchange-database/iterate_active_auditors.h" 120 #include "exchange-database/iterate_active_signkeys.h" 121 #include "exchange-database/iterate_auditor_denominations.h" 122 #include "exchange-database/iterate_denomination_info.h" 123 #include "exchange-database/iterate_denominations.h" 124 #include "exchange-database/iterate_kyc_reference.h" 125 #include "exchange-database/iterate_reserve_close_info.h" 126 #include "exchange-database/kycauth_in_insert.h" 127 #include "exchange-database/kyc_provider_account_lookup.h" 128 #include "exchange-database/lookup_active_legitimization.h" 129 #include "exchange-database/lookup_aml_file_number.h" 130 #include "exchange-database/lookup_aml_history.h" 131 #include "exchange-database/lookup_aml_officer.h" 132 #include "exchange-database/lookup_auditor_status.h" 133 #include "exchange-database/lookup_auditor_timestamp.h" 134 #include "exchange-database/lookup_completed_legitimization.h" 135 #include "exchange-database/lookup_denomination_key.h" 136 #include "exchange-database/lookup_global_fee_by_time.h" 137 #include "exchange-database/lookup_h_payto_by_access_token.h" 138 #include "exchange-database/lookup_kyc_history.h" 139 #include "exchange-database/lookup_kyc_process_by_account.h" 140 #include "exchange-database/lookup_kyc_requirement_by_row.h" 141 #include "exchange-database/lookup_kyc_status_by_token.h" 142 #include "exchange-database/lookup_pending_legitimization.h" 143 #include "exchange-database/lookup_records_by_table.h" 144 #include "exchange-database/lookup_rules_by_access_token.h" 145 #include "exchange-database/lookup_serial_by_table.h" 146 #include "exchange-database/lookup_signing_key.h" 147 #include "exchange-database/lookup_signkey_revocation.h" 148 #include "exchange-database/lookup_transfer_by_deposit.h" 149 #include "exchange-database/lookup_wire_fee_by_time.h" 150 #include "exchange-database/lookup_wire_timestamp.h" 151 #include "exchange-database/lookup_wire_transfer.h" 152 #include "exchange-database/mark_refresh_reveal_success.h" 153 #include "exchange-database/persist_kyc_attributes.h" 154 #include "exchange-database/persist_policy_details.h" 155 #include "exchange-database/preflight.h" 156 #include "exchange-database/profit_drains_get_pending.h" 157 #include "exchange-database/profit_drains_set_finished.h" 158 #include "exchange-database/release_revolving_shard.h" 159 #include "exchange-database/reserves_get.h" 160 #include "exchange-database/reserves_get_origin.h" 161 #include "exchange-database/reserves_in_insert.h" 162 #include "exchange-database/reserves_update.h" 163 #include "exchange-database/rollback.h" 164 #include "exchange-database/select_account_merges_above_serial_id.h" 165 #include "exchange-database/select_aggregation_amounts_for_kyc_check.h" 166 #include "exchange-database/select_aggregations_above_serial.h" 167 #include "exchange-database/select_aggregation_transient.h" 168 #include "exchange-database/select_all_kyc_attributes.h" 169 #include "exchange-database/select_all_purse_decisions_above_serial_id.h" 170 #include "exchange-database/select_all_purse_deletions_above_serial_id.h" 171 #include "exchange-database/select_aml_attributes.h" 172 #include "exchange-database/select_aml_decisions.h" 173 #include "exchange-database/select_aml_measures.h" 174 #include "exchange-database/select_aml_statistics.h" 175 #include "exchange-database/select_auditor_denom_sig.h" 176 #include "exchange-database/select_batch_deposits_missing_wire.h" 177 #include "exchange-database/select_coin_deposits_above_serial_id.h" 178 #include "exchange-database/select_contract_by_purse.h" 179 #include "exchange-database/select_contract.h" 180 #include "exchange-database/select_deposit_amounts_for_kyc_check.h" 181 #include "exchange-database/select_exchange_credit_transfers.h" 182 #include "exchange-database/select_exchange_debit_transfers.h" 183 #include "exchange-database/select_exchange_kycauth_transfers.h" 184 #include "exchange-database/select_kyc_accounts.h" 185 #include "exchange-database/select_kyc_attributes.h" 186 #include "exchange-database/select_merge_amounts_for_kyc_check.h" 187 #include "exchange-database/select_purse_by_merge_pub.h" 188 #include "exchange-database/select_purse_decisions_above_serial_id.h" 189 #include "exchange-database/select_purse_deposits_above_serial_id.h" 190 #include "exchange-database/select_purse_deposits_by_purse.h" 191 #include "exchange-database/select_purse.h" 192 #include "exchange-database/select_purse_merge.h" 193 #include "exchange-database/select_purse_merges_above_serial_id.h" 194 #include "exchange-database/select_purse_requests_above_serial_id.h" 195 #include "exchange-database/select_recoup_above_serial_id.h" 196 #include "exchange-database/select_recoup_refresh_above_serial_id.h" 197 #include "exchange-database/select_refreshes_above_serial_id.h" 198 #include "exchange-database/select_refunds_above_serial_id.h" 199 #include "exchange-database/select_refunds_by_coin.h" 200 #include "exchange-database/select_reserve_closed_above_serial_id.h" 201 #include "exchange-database/select_reserve_close_info.h" 202 #include "exchange-database/select_reserve_open_above_serial_id.h" 203 #include "exchange-database/select_reserves_in_above_serial_id.h" 204 #include "exchange-database/select_wire_out_above_serial_id_by_account.h" 205 #include "exchange-database/select_wire_out_above_serial_id.h" 206 #include "exchange-database/select_withdrawals_above_serial_id.h" 207 #include "exchange-database/select_withdraw_amounts_for_kyc_check.h" 208 #include "exchange-database/set_aml_lock.h" 209 #include "exchange-database/set_extension_manifest.h" 210 #include "exchange-database/set_purse_balance.h" 211 #include "exchange-database/start_deferred_wire_out.h" 212 #include "exchange-database/start.h" 213 #include "exchange-database/start_read_committed.h" 214 #include "exchange-database/start_read_only.h" 215 #include "exchange-database/store_wire_transfer_out.h" 216 #include "exchange-database/test_aml_officer.h" 217 #include "exchange-database/trigger_kyc_rule_for_account.h" 218 #include "exchange-database/update_aggregation_transient.h" 219 #include "exchange-database/update_auditor.h" 220 #include "exchange-database/update_kyc_process_by_row.h" 221 #include "exchange-database/update_wire.h" 222 #include "exchange-database/wad_in_insert.h" 223 #include "exchange-database/wire_prepare_data_get.h" 224 #include "exchange-database/wire_prepare_data_insert.h" 225 #include "exchange-database/wire_prepare_data_mark_failed.h" 226 #include "exchange-database/wire_prepare_data_mark_finished.h" 227 228 229 /** 230 * Handle to access the exchange's source database. 231 */ 232 static struct TALER_EXCHANGEDB_PostgresContext *src; 233 234 /** 235 * Handle to access the exchange's destination database. 236 */ 237 static struct TALER_EXCHANGEDB_PostgresContext *dst; 238 239 /** 240 * Return value from #main(). 241 */ 242 static int global_ret; 243 244 /** 245 * Main task to do synchronization. 246 */ 247 static struct GNUNET_SCHEDULER_Task *sync_task; 248 249 /** 250 * What is our target transaction size (number of records)? 251 */ 252 static unsigned int transaction_size = 512; 253 254 /** 255 * Number of records copied in this transaction. 256 */ 257 static unsigned long long actual_size; 258 259 /** 260 * Terminate once synchronization is achieved. 261 */ 262 static int exit_if_synced; 263 264 265 /** 266 * Information we track per replicated table. 267 */ 268 struct Table 269 { 270 /** 271 * Which table is this record about? 272 */ 273 enum TALER_EXCHANGEDB_ReplicatedTable rt; 274 275 /** 276 * Up to which record is the destination table synchronized. 277 */ 278 uint64_t start_serial; 279 280 /** 281 * Highest serial in the source table. 282 */ 283 uint64_t end_serial; 284 285 /** 286 * Marker for the end of the list of #tables. 287 */ 288 bool end; 289 }; 290 291 292 /** 293 * Information about replicated tables. 294 */ 295 static struct Table tables[] = { 296 { .rt = TALER_EXCHANGEDB_RT_DENOMINATIONS}, 297 { .rt = TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS}, 298 { .rt = TALER_EXCHANGEDB_RT_KYC_TARGETS}, 299 { .rt = TALER_EXCHANGEDB_RT_WIRE_TARGETS}, 300 { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_MEASURES}, 301 { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_OUTCOMES}, 302 { .rt = TALER_EXCHANGEDB_RT_LEGITIMIZATION_PROCESSES}, 303 { .rt = TALER_EXCHANGEDB_RT_RESERVES}, 304 { .rt = TALER_EXCHANGEDB_RT_RESERVES_IN}, 305 { .rt = TALER_EXCHANGEDB_RT_RESERVES_CLOSE}, 306 { .rt = TALER_EXCHANGEDB_RT_RESERVES_OPEN_REQUESTS}, 307 { .rt = TALER_EXCHANGEDB_RT_RESERVES_OPEN_DEPOSITS}, 308 { .rt = TALER_EXCHANGEDB_RT_WITHDRAW}, 309 { .rt = TALER_EXCHANGEDB_RT_AUDITORS}, 310 { .rt = TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS}, 311 { .rt = TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS}, 312 { .rt = TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS}, 313 { .rt = TALER_EXCHANGEDB_RT_KNOWN_COINS}, 314 { .rt = TALER_EXCHANGEDB_RT_REFRESH}, 315 { .rt = TALER_EXCHANGEDB_RT_BATCH_DEPOSITS}, 316 { .rt = TALER_EXCHANGEDB_RT_COIN_DEPOSITS}, 317 { .rt = TALER_EXCHANGEDB_RT_REFUNDS}, 318 { .rt = TALER_EXCHANGEDB_RT_WIRE_OUT}, 319 { .rt = TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING}, 320 { .rt = TALER_EXCHANGEDB_RT_WIRE_FEE}, 321 { .rt = TALER_EXCHANGEDB_RT_GLOBAL_FEE}, 322 { .rt = TALER_EXCHANGEDB_RT_RECOUP}, 323 { .rt = TALER_EXCHANGEDB_RT_RECOUP_REFRESH }, 324 { .rt = TALER_EXCHANGEDB_RT_EXTENSIONS}, 325 { .rt = TALER_EXCHANGEDB_RT_POLICY_DETAILS }, 326 { .rt = TALER_EXCHANGEDB_RT_POLICY_FULFILLMENTS }, 327 { .rt = TALER_EXCHANGEDB_RT_PURSE_REQUESTS}, 328 { .rt = TALER_EXCHANGEDB_RT_PURSE_DECISION}, 329 { .rt = TALER_EXCHANGEDB_RT_PURSE_MERGES}, 330 { .rt = TALER_EXCHANGEDB_RT_PURSE_DEPOSITS}, 331 { .rt = TALER_EXCHANGEDB_RT_ACCOUNT_MERGES}, 332 { .rt = TALER_EXCHANGEDB_RT_HISTORY_REQUESTS}, 333 { .rt = TALER_EXCHANGEDB_RT_CLOSE_REQUESTS}, 334 { .rt = TALER_EXCHANGEDB_RT_WADS_OUT}, 335 { .rt = TALER_EXCHANGEDB_RT_WADS_OUT_ENTRIES}, 336 { .rt = TALER_EXCHANGEDB_RT_WADS_IN}, 337 { .rt = TALER_EXCHANGEDB_RT_WADS_IN_ENTRIES}, 338 { .rt = TALER_EXCHANGEDB_RT_PROFIT_DRAINS}, 339 { .end = true } 340 }; 341 342 343 /** 344 * Closure for #do_insert. 345 */ 346 struct InsertContext 347 { 348 /** 349 * Table we are replicating. 350 */ 351 struct Table *table; 352 353 /** 354 * Set to error if insertion created an error. 355 */ 356 enum GNUNET_DB_QueryStatus qs; 357 }; 358 359 360 /** 361 * Function called on data to replicate in the auditor's database. 362 * 363 * @param cls closure, a `struct InsertContext` 364 * @param td record from an exchange table 365 * @return #GNUNET_OK to continue to iterate, 366 * #GNUNET_SYSERR to fail with an error 367 */ 368 static enum GNUNET_GenericReturnValue 369 do_insert (void *cls, 370 const struct TALER_EXCHANGEDB_TableData *td) 371 { 372 struct InsertContext *ctx = cls; 373 enum GNUNET_DB_QueryStatus qs; 374 375 if (0 >= ctx->qs) 376 return GNUNET_SYSERR; 377 qs = TALER_EXCHANGEDB_insert_records_by_table (dst, 378 td); 379 if (0 >= qs) 380 { 381 switch (qs) 382 { 383 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 384 GNUNET_assert (0); 385 break; 386 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 387 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 388 "Failed to insert record into table %d: no change\n", 389 td->table); 390 break; 391 case GNUNET_DB_STATUS_SOFT_ERROR: 392 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 393 "Serialization error inserting record into table %d (will retry)\n", 394 td->table); 395 break; 396 case GNUNET_DB_STATUS_HARD_ERROR: 397 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 398 "Failed to insert record into table %d: hard error\n", 399 td->table); 400 break; 401 } 402 ctx->qs = qs; 403 return GNUNET_SYSERR; 404 } 405 actual_size++; 406 ctx->table->start_serial = td->serial; 407 return GNUNET_OK; 408 } 409 410 411 /** 412 * Run one replication transaction. 413 * 414 * @return #GNUNET_OK on success, #GNUNET_SYSERR to rollback 415 */ 416 static enum GNUNET_GenericReturnValue 417 transact (void) 418 { 419 struct InsertContext ctx = { 420 .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT 421 }; 422 423 if (0 > 424 TALER_EXCHANGEDB_start (src, 425 "lookup src serials")) 426 return GNUNET_SYSERR; 427 for (unsigned int i = 0; ! tables[i].end; i++) 428 TALER_EXCHANGEDB_lookup_serial_by_table (src, 429 tables[i].rt, 430 &tables[i].end_serial); 431 TALER_EXCHANGEDB_rollback (src); 432 if (GNUNET_OK != 433 TALER_EXCHANGEDB_start (dst, 434 "lookup dst serials")) 435 return GNUNET_SYSERR; 436 for (unsigned int i = 0; ! tables[i].end; i++) 437 TALER_EXCHANGEDB_lookup_serial_by_table (dst, 438 tables[i].rt, 439 &tables[i].start_serial); 440 TALER_EXCHANGEDB_rollback (dst); 441 for (unsigned int i = 0; ! tables[i].end; i++) 442 { 443 struct Table *table = &tables[i]; 444 445 if (table->start_serial == table->end_serial) 446 continue; 447 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 448 "Replicating table %d from %llu to %llu\n", 449 i, 450 (unsigned long long) table->start_serial, 451 (unsigned long long) table->end_serial); 452 ctx.table = table; 453 while (table->start_serial < table->end_serial) 454 { 455 enum GNUNET_DB_QueryStatus qs; 456 457 if (GNUNET_OK != 458 TALER_EXCHANGEDB_start (src, 459 "copy table (src)")) 460 return GNUNET_SYSERR; 461 if (GNUNET_OK != 462 TALER_EXCHANGEDB_start (dst, 463 "copy table (dst)")) 464 return GNUNET_SYSERR; 465 qs = TALER_EXCHANGEDB_lookup_records_by_table (src, 466 table->rt, 467 table->start_serial, 468 &do_insert, 469 &ctx); 470 if (ctx.qs < 0) 471 qs = ctx.qs; 472 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 473 { 474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 475 "Failed to lookup records from table %d: hard error\n", 476 i); 477 global_ret = EXIT_FAILURE; 478 return GNUNET_SYSERR; 479 } 480 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 481 { 482 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 483 "Serialization error looking up records from table %d (will retry)\n", 484 i); 485 return GNUNET_SYSERR; /* will retry */ 486 } 487 if (0 == qs) 488 { 489 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 490 "Failed to lookup records from table %d: no results\n", 491 i); 492 GNUNET_break (0); /* should be impossible */ 493 global_ret = EXIT_FAILURE; 494 return GNUNET_SYSERR; 495 } 496 if (0 == ctx.qs) 497 return GNUNET_SYSERR; /* insertion failed, maybe record existed? try again */ 498 TALER_EXCHANGEDB_rollback (src); 499 qs = TALER_EXCHANGEDB_commit (dst); 500 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 501 { 502 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 503 "Serialization error committing transaction on table %d (will retry)\n", 504 i); 505 continue; 506 } 507 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 508 { 509 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 510 "Hard error committing transaction on table %d\n", 511 i); 512 global_ret = EXIT_FAILURE; 513 return GNUNET_SYSERR; 514 } 515 } 516 } 517 /* we do not care about conflicting UPDATEs to src table, so safe to just rollback */ 518 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 519 "Sync pass completed successfully with %llu updates\n", 520 actual_size); 521 return GNUNET_OK; 522 } 523 524 525 /** 526 * Task to do the actual synchronization work. 527 * 528 * @param cls NULL, unused 529 */ 530 static void 531 do_sync (void *cls) 532 { 533 static struct GNUNET_TIME_Relative delay; 534 535 (void) cls; 536 sync_task = NULL; 537 actual_size = 0; 538 if (GNUNET_SYSERR == 539 TALER_EXCHANGEDB_preflight (src)) 540 { 541 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 542 "Failed to begin transaction with data source. Exiting\n"); 543 return; 544 } 545 if (GNUNET_SYSERR == 546 TALER_EXCHANGEDB_preflight (dst)) 547 { 548 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 549 "Failed to begin transaction with data destination. Exiting\n"); 550 return; 551 } 552 if (GNUNET_OK != transact ()) 553 { 554 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 555 "Transaction failed, rolling back\n"); 556 TALER_EXCHANGEDB_rollback (src); 557 TALER_EXCHANGEDB_rollback (dst); 558 } 559 if (0 != global_ret) 560 { 561 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 562 "Transaction failed permanently, exiting\n"); 563 return; 564 } 565 if ( (0 == actual_size) && 566 (exit_if_synced) ) 567 { 568 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 569 "Databases are synchronized. Exiting\n"); 570 return; 571 } 572 if (actual_size < transaction_size / 2) 573 { 574 delay = GNUNET_TIME_STD_BACKOFF (delay); 575 } 576 else if (actual_size >= transaction_size) 577 { 578 delay = GNUNET_TIME_UNIT_ZERO; 579 } 580 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 581 "Next sync pass in %s\n", 582 GNUNET_STRINGS_relative_time_to_string (delay, 583 GNUNET_YES)); 584 sync_task = GNUNET_SCHEDULER_add_delayed (delay, 585 &do_sync, 586 NULL); 587 } 588 589 590 /** 591 * Set an option of type 'char *' from the command line with 592 * filename expansion a la #GNUNET_STRINGS_filename_expand(). 593 * 594 * @param ctx command line processing context 595 * @param scls additional closure (will point to the `char *`, 596 * which will be allocated) 597 * @param option name of the option 598 * @param value actual value of the option (a string) 599 * @return #GNUNET_OK 600 */ 601 static enum GNUNET_GenericReturnValue 602 set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, 603 void *scls, 604 const char *option, 605 const char *value) 606 { 607 char **val = scls; 608 609 (void) ctx; 610 (void) option; 611 GNUNET_assert (NULL != value); 612 GNUNET_free (*val); 613 *val = GNUNET_STRINGS_filename_expand (value); 614 return GNUNET_OK; 615 } 616 617 618 /** 619 * Allow user to specify configuration file name (-s option) 620 * 621 * @param[out] fn set to the name of the configuration file 622 */ 623 static struct GNUNET_GETOPT_CommandLineOption 624 option_cfgfile_src (char **fn) 625 { 626 struct GNUNET_GETOPT_CommandLineOption clo = { 627 .shortName = 's', 628 .name = "source-configuration", 629 .argumentHelp = "FILENAME", 630 .description = gettext_noop ( 631 "use configuration file FILENAME for the SOURCE database"), 632 .require_argument = 1, 633 .processor = &set_filename, 634 .scls = (void *) fn 635 }; 636 637 return clo; 638 } 639 640 641 /** 642 * Allow user to specify configuration file name (-d option) 643 * 644 * @param[out] fn set to the name of the configuration file 645 */ 646 static struct GNUNET_GETOPT_CommandLineOption 647 option_cfgfile_dst (char **fn) 648 { 649 struct GNUNET_GETOPT_CommandLineOption clo = { 650 .shortName = 'd', 651 .name = "destination-configuration", 652 .argumentHelp = "FILENAME", 653 .description = gettext_noop ( 654 "use configuration file FILENAME for the DESTINATION database"), 655 .require_argument = 1, 656 .processor = &set_filename, 657 .scls = (void *) fn 658 }; 659 660 return clo; 661 } 662 663 664 static struct GNUNET_CONFIGURATION_Handle * 665 load_config (const char *cfgfile) 666 { 667 struct GNUNET_CONFIGURATION_Handle *cfg; 668 669 cfg = GNUNET_CONFIGURATION_create (TALER_AUDITOR_project_data ()); 670 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 671 "Loading config file: %s\n", 672 cfgfile); 673 if (GNUNET_SYSERR == 674 GNUNET_CONFIGURATION_load (cfg, 675 cfgfile)) 676 { 677 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 678 "Malformed configuration file `%s', exit ...\n", 679 cfgfile); 680 GNUNET_CONFIGURATION_destroy (cfg); 681 return NULL; 682 } 683 return cfg; 684 } 685 686 687 /** 688 * Shutdown task. 689 * 690 * @param cls NULL, unused 691 */ 692 static void 693 do_shutdown (void *cls) 694 { 695 (void) cls; 696 if (NULL != sync_task) 697 { 698 GNUNET_SCHEDULER_cancel (sync_task); 699 sync_task = NULL; 700 } 701 } 702 703 704 /** 705 * Initial task. 706 * 707 * @param cls NULL, unused 708 */ 709 static void 710 run (void *cls) 711 { 712 (void) cls; 713 714 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 715 NULL); 716 sync_task = GNUNET_SCHEDULER_add_now (&do_sync, 717 NULL); 718 } 719 720 721 /** 722 * Setup plugins in #src and #dst and #run() the main 723 * logic with those plugins. 724 */ 725 static void 726 setup (struct GNUNET_CONFIGURATION_Handle *src_cfg, 727 struct GNUNET_CONFIGURATION_Handle *dst_cfg) 728 { 729 src = TALER_EXCHANGEDB_connect (src_cfg, 730 false); 731 if (NULL == src) 732 { 733 global_ret = EXIT_NOTINSTALLED; 734 return; 735 } 736 dst = TALER_EXCHANGEDB_connect (dst_cfg, 737 false); 738 if (NULL == dst) 739 { 740 global_ret = EXIT_NOTINSTALLED; 741 TALER_EXCHANGEDB_disconnect (src); 742 src = NULL; 743 return; 744 } 745 GNUNET_SCHEDULER_run (&run, 746 NULL); 747 TALER_EXCHANGEDB_disconnect (src); 748 src = NULL; 749 TALER_EXCHANGEDB_disconnect (dst); 750 dst = NULL; 751 } 752 753 754 /** 755 * The main function of the taler-auditor-exchange tool. This tool is used 756 * to add (or remove) an exchange's master key and base URL to the auditor's 757 * database. 758 * 759 * @param argc number of arguments from the command line 760 * @param argv command line arguments 761 * @return 0 ok, non-zero on error 762 */ 763 int 764 main (int argc, 765 char *const *argv) 766 { 767 char *src_cfgfile = NULL; 768 char *dst_cfgfile = NULL; 769 char *level = GNUNET_strdup ("WARNING"); 770 struct GNUNET_CONFIGURATION_Handle *src_cfg; 771 struct GNUNET_CONFIGURATION_Handle *dst_cfg; 772 const struct GNUNET_GETOPT_CommandLineOption options[] = { 773 GNUNET_GETOPT_option_mandatory ( 774 option_cfgfile_src (&src_cfgfile)), 775 GNUNET_GETOPT_option_mandatory ( 776 option_cfgfile_dst (&dst_cfgfile)), 777 GNUNET_GETOPT_option_help ( 778 TALER_AUDITOR_project_data (), 779 gettext_noop ("Make a safe copy of an exchange database")), 780 GNUNET_GETOPT_option_uint ( 781 'b', 782 "batch", 783 "SIZE", 784 gettext_noop ( 785 "target SIZE for a the number of records to copy in one transaction"), 786 &transaction_size), 787 GNUNET_GETOPT_option_flag ( 788 't', 789 "terminate-when-synchronized", 790 gettext_noop ( 791 "terminate as soon as the databases are synchronized"), 792 &exit_if_synced), 793 GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION), 794 GNUNET_GETOPT_option_loglevel (&level), 795 GNUNET_GETOPT_OPTION_END 796 }; 797 798 TALER_gcrypt_init (); /* must trigger initialization manually at this point! */ 799 { 800 int ret; 801 802 ret = GNUNET_GETOPT_run ("taler-auditor-sync", 803 options, 804 argc, argv); 805 if (GNUNET_NO == ret) 806 return EXIT_SUCCESS; 807 if (GNUNET_SYSERR == ret) 808 return EXIT_INVALIDARGUMENT; 809 } 810 GNUNET_assert (GNUNET_OK == 811 GNUNET_log_setup ("taler-auditor-sync", 812 level, 813 NULL)); 814 GNUNET_free (level); 815 /* suppress compiler warnings... */ 816 GNUNET_assert (NULL != src_cfgfile); 817 GNUNET_assert (NULL != dst_cfgfile); 818 if (0 == strcmp (src_cfgfile, 819 dst_cfgfile)) 820 { 821 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 822 "Source and destination configuration files must differ!\n"); 823 return EXIT_INVALIDARGUMENT; 824 } 825 src_cfg = load_config (src_cfgfile); 826 if (NULL == src_cfg) 827 { 828 GNUNET_free (src_cfgfile); 829 GNUNET_free (dst_cfgfile); 830 return EXIT_NOTCONFIGURED; 831 } 832 dst_cfg = load_config (dst_cfgfile); 833 if (NULL == dst_cfg) 834 { 835 GNUNET_CONFIGURATION_destroy (src_cfg); 836 GNUNET_free (src_cfgfile); 837 GNUNET_free (dst_cfgfile); 838 return EXIT_NOTCONFIGURED; 839 } 840 setup (src_cfg, 841 dst_cfg); 842 GNUNET_CONFIGURATION_destroy (src_cfg); 843 GNUNET_CONFIGURATION_destroy (dst_cfg); 844 GNUNET_free (src_cfgfile); 845 GNUNET_free (dst_cfgfile); 846 847 return global_ret; 848 } 849 850 851 /* end of taler-auditor-sync.c */