taler-wallet-developer.rst (29512B)
1 .. 2 This file is part of GNU TALER. 3 Copyright (C) 2014-2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3.0, 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 Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 16 17 Wallet Developer Manual 18 ####################### 19 20 .. note:: 21 22 This manual contains information for developers working on the wallet 23 component of GNU Taler. It is not intended for a general audience. 24 25 26 The GNU Taler wallet allows customers to withdraw and spend digital cash. 27 28 Additional implementation notes about request retries, cancellation, and 29 failure reporting are documented in :doc:`../wallet/wallet-error-handling`. 30 31 .. toctree:: 32 :hidden: 33 34 ../wallet/wallet-error-handling 35 36 37 WebExtension Wallet 38 =================== 39 40 Building from source 41 -------------------- 42 43 .. code-block:: console 44 45 $ git clone https://git.taler.net/wallet-core.git 46 $ cd wallet-core 47 $ ./configure 48 $ make webex-stable 49 # Packaged extension now available as: 50 # dist/taler-wallet-$VERSION.zip 51 52 53 Android Wallet 54 ============== 55 56 Please see :ref:`Build-apps-from-source` in the :doc:`taler-developer-manual`. 57 58 59 iOS Wallet 60 ========== 61 62 Please see :ref:`Build-iOS-from-source` in the :doc:`taler-developer-manual`. 63 64 .. _command-line-wallet: 65 66 Command-line Wallet 67 =================== 68 69 This section describes how to use the GNU Taler wallet command line 70 interface (CLI). 71 72 The wallet CLI is targeted at developers and operators, but not meant to be 73 used by customers. It exposes all functionality that the more user-friendly 74 interfaces (Android app, browser extension) offer. However, it provides more 75 diagnostics and advanced features as well. 76 77 Building from source 78 -------------------- 79 80 The easiest way to install the wallet is via NPM. Note that a recent version of 81 Node.JS (``>=12.20.1``) is required. 82 83 We recommend to install the wallet package on a per-user basis, 84 thus setting ``$INSTALL_PREFIX`` to a directory in ``$HOME``. 85 86 .. code-block:: console 87 88 $ git clone https://git.taler.net/wallet-core.git 89 $ cd wallet-core 90 $ ./bootstrap 91 $ ./configure --prefix=$INSTALL_PREFIX 92 $ make && make install 93 94 The wallet command-line interface should then be available as ``taler-wallet-cli`` under ``$INSTALL_PREFIX/bin``. 95 96 Installation via NPM 97 -------------------- 98 99 The wallet can also obtained via NPM, the Node Package Manager. 100 101 To install the wallet as a global package, run: 102 103 .. code-block:: console 104 105 $ npm install -g taler-wallet 106 # check if installation was successful 107 $ taler-wallet-cli --version 108 109 To install the wallet only for your user, run: 110 111 .. code-block:: console 112 113 $ npm install -g --prefix=$HOME/local taler-wallet 114 # check if installation was successful 115 $ taler-wallet-cli --version 116 # If this fails, make sure that $HOME/local/bin is in your $PATH 117 118 To use the wallet as a library in your own project, run: 119 120 .. code-block:: console 121 122 $ npm install taler-wallet 123 124 125 Getting Help 126 ------------ 127 128 The wallet CLI comes with built-in help. Invoke the wallet CLI (or any subcommand) with the ``--help`` flag to get help: 129 130 .. code-block:: console 131 132 $ taler-wallet-cli --help 133 Usage: taler-wallet-cli COMMAND 134 135 Command line interface for the GNU Taler wallet. 136 137 Options: 138 -h, --help Show this message and exit. 139 --wallet-db=VALUE location of the wallet database file 140 --timetravel=VALUE modify system time by given offset in microseconds 141 --inhibit=VALUE Inhibit running certain operations, useful for debugging and testing. 142 --no-throttle Don't do any request throttling. 143 -v, --version 144 -V, --verbose Enable verbose output. 145 146 Commands: 147 advanced Subcommands for advanced operations (only use if you know what you're doing!). 148 api Call the wallet-core API directly. 149 backup Subcommands for backups 150 balance Show wallet balance. 151 deposit Subcommands for depositing money to payto:// accounts 152 exchanges Manage exchanges. 153 handle-uri Handle a taler:// URI. 154 pending Show pending operations. 155 run-pending Run pending operations. 156 run-until-done Run until no more work is left. 157 testing Subcommands for testing GNU Taler deployments. 158 transactions Show transactions. 159 160 Completing operations 161 --------------------- 162 163 Note that the CLI does not run as a background daemon. When starting 164 operations that don't immediately finish, the wallet needs to be run explicitly 165 to finish any pending tasks: 166 167 168 .. code-block:: console 169 170 # Do one attempt to finish all pending operations 171 $ taler-wallet-cli run-pending 172 173 # Run until all work is done 174 $ taler-wallet-cli run-until-done 175 176 Resetting the wallet 177 -------------------- 178 179 The wallet can be reset by deleting its database file. By default, the database file 180 is ``$HOME/.talerwalletdb.sqlite3``. 181 182 183 Handling taler:// URIs 184 ---------------------- 185 186 Many interactions with the Taler wallet happen by scanning QR codes or special 187 headers on Websites. To emulate this with the command line interface, run the following 188 command: 189 190 .. code-block:: console 191 192 $ taler-wallet-cli handle-uri $URI 193 194 195 Manual withdrawing 196 ------------------ 197 198 .. code-block:: console 199 200 $ taler-wallet-cli advanced withdraw-manually \ 201 --exchange https://exchange.eurint.taler.net/ \ 202 --amount EUR:5 203 204 205 P2P push payments 206 ----------------- 207 208 The following code generates a P2P push transaction over 1 CHF 209 with an expiration time of 30 days (assuming the wallet has a 210 sufficient balance): 211 212 .. code-block:: console 213 214 $ taler-wallet-cli p2p initiate-push-debit \ 215 --purse-expiration="30 d" \ 216 --summary="The summary" \ 217 CHF:1 218 219 The final URL can then be found in the transaction list: 220 221 .. code-block:: console 222 223 $ taler-wallet-cli transactions 224 225 Background wallet 226 ----------------- 227 228 A wallet can be launched in the background: 229 230 .. code-block:: console 231 232 $ taler-wallet-cli advanced serve & 233 234 You can then run various Taler operations faster against 235 this one persistent instance: 236 237 .. code-block:: console 238 239 $ taler-wallet-cli --wallet-connection=wallet-core.sock ... 240 241 Here ``...`` needs to be changed to the commando to run. 242 Make sure to run 243 244 .. code-block:: console 245 246 $ taler-wallet-cli --wallet-connection=wallet-core.sock \ 247 run-until-done 248 249 to wait for pending transactions to complete. 250 251 252 Testing an exchange deployment 253 ------------------------------ 254 255 The following series of commands can be used to check that an exchange deployment 256 is functional: 257 258 .. code-block:: console 259 260 # This will now output a payto URI that money needs to be sent to in order to allow withdrawal 261 # of taler coins 262 $ taler-wallet-cli advanced withdraw-manually --exchange $EXCHANGE_URL --amount EUR:10.50 263 264 # Show the status of the manual withdrawal operation 265 $ taler-wallet-cli transactions 266 267 # Once the transfer has been made, try completing the withdrawal 268 $ taler-wallet-cli run-pending 269 270 # Check status of transactions and show balance 271 $ taler-wallet-cli transactions 272 $ taler-wallet-cli balance 273 274 # Now, directly deposit coins with the exchange into a target account 275 # (Usually, a payment is made via a merchant. The wallet provides 276 # this functionality for testing.) 277 $ taler-wallet-cli deposit create EUR:5 payto://iban/$IBAN 278 279 # Check if transaction was successful. 280 # (If not, fix issue with exchange and run "run-pending" command again) 281 $ taler-wallet-cli transactions 282 283 # The wallet can also track if the exchange wired the money to the merchant account. 284 # The "deposit group id" can be found in the output of the transactions list. 285 $ taler-wallet-cli deposit track $DEPOSIT_GROUP_ID 286 287 288 APIs and Data Formats 289 ===================== 290 291 Envelope Format 292 --------------- 293 294 All API responses and notifications are returned in the 295 following envelope: 296 297 .. ts:def:: WalletResponseEnvelope 298 299 type WalletResponseEnvelope = 300 | WalletSuccess 301 | WalletError 302 | WalletNotification 303 304 .. ts:def:: WalletSuccess 305 306 export interface WalletSuccess { 307 type: "response"; 308 operation: string; 309 // ID to correlate success response to request 310 id: string; 311 // Result type depends on operation 312 result: unknown; 313 } 314 315 .. ts:def:: WalletError 316 317 export interface WalletError { 318 type: "error"; 319 operation: string; 320 // ID to correlate error response to request 321 id: string; 322 error: WalletErrorInfo; 323 } 324 325 .. ts:def:: WalletNotification 326 327 export interface WalletSuccess { 328 type: "notification"; 329 330 // actual type is WalletNotification, 331 // to be documented here 332 payload: any; 333 } 334 335 .. ts:def:: WalletErrorInfo 336 337 export interface WalletErrorInfo { 338 // Numeric error code defined defined in the 339 // GANA gnu-taler-error-codes registry. 340 talerErrorCode: number; 341 342 // English description of the error code. 343 talerErrorHint: string; 344 345 // English diagnostic message that can give details 346 // for the instance of the error. 347 message: string; 348 349 // Error details, type depends 350 // on talerErrorCode 351 details: unknown; 352 } 353 354 Withdrawal 355 ---------- 356 357 A typical API sequence for *bank-integrated* withdrawals can for example look like this: 358 359 #. ``"getWithdrawalDetailsForUri"`` returns an amount and default exchange 360 #. ``"getWithdrawalDetailsForAmount"`` returns fee information and that ToS are not accepted 361 362 #. ``"getExchangeTos"`` are shown to the user and return currentEtag 363 #. ``"setExchangeTosAccepted"`` called with currentEtag after user accepted 364 365 #. ``"acceptWithdrawal"`` after the user confirmed withdrawal with associated fees 366 367 A typical API sequence for *manual* withdrawals can for example look like this: 368 369 #. ``"listExchanges"`` shows a list of exchanges to the user who picks one and an amount 370 #. ``"getWithdrawalDetailsForAmount"`` returns fee information and that ToS are not accepted 371 372 #. ``"getExchangeTos"`` are shown to the user and return currentEtag 373 #. ``"setExchangeTosAccepted"`` called with currentEtag after user accepted 374 375 #. ``"acceptManualWithdrawal"`` after the user confirmed withdrawal with associated fees 376 377 Integration Tests 378 ================= 379 380 Integration Test Example 381 ------------------------ 382 383 Integration tests can be done with the low-level wallet commands. To select which coins and denominations 384 to use, the wallet can dump the coins in an easy-to-process format (`CoinDumpJson <https://git.taler.net/taler-typescript-core.git/tree/packages/taler-util/src/types-taler-wallet.ts#n613>`__). 385 386 The database file for the wallet can be selected with the ``--wallet-db`` 387 option. This option must be passed to the ``taler-wallet-cli`` command and not 388 the subcommands. If the database file doesn't exist, it will be created. 389 390 The following example does a simple withdrawal recoup: 391 392 .. code-block:: console 393 394 # Withdraw digital cash 395 $ taler-wallet-cli --wallet-db=mydb.sqlite3 testing withdraw \ 396 -b https://bank.int.taler.net/ \ 397 -e https://exchange.int.taler.net/ \ 398 -a INTKUDOS:10 399 400 $ coins=$(taler-wallet-cli --wallet-db=mydb.sqlite3 advanced dump-coins) 401 402 # Find coin we want to revoke 403 $ rc=$(echo "$coins" | \ 404 jq -r '[.coins[] | select((.denom_value == "INTKUDOS:5"))][0] | .coin_pub') 405 406 # Find the denom 407 $ rd=$(echo "$coins" | \ 408 jq -r '[.coins[] | select((.denom_value == "INTKUDOS:5"))][0] | .denom_pub_hash') 409 410 # Find all other coins, which will be suspended 411 $ susp=$(echo "$coins" | \ 412 jq --arg rc "$rc" '[.coins[] | select(.coin_pub != $rc) | .coin_pub]') 413 414 # The exchange revokes the denom 415 $ taler-exchange-keyup -r $rd 416 $ taler-deployment-restart 417 418 # Now we suspend the other coins, so later we will pay with the recouped coin 419 $ taler-wallet-cli --wallet-db=mydb.sqlite3 advanced suspend-coins "$susp" 420 421 # Update exchange /keys so recoup gets scheduled 422 $ taler-wallet-cli --wallet-db=mydb.sqlite3 exchanges update -f https://exchange.int.taler.net/ 423 424 # Block until scheduled operations are done 425 $ taler-wallet-cli --wallet-db=mydb.sqlite3 run-until-done 426 427 # Now we buy something, only the coins resulting from recouped will be 428 # used, as other ones are suspended 429 $ taler-wallet-cli --wallet-db=mydb.sqlite3 testing test-pay \ 430 -m https://backend.int.taler.net/ \ 431 -k sandbox \ 432 -a "INTKUDOS:1" \ 433 -s "foo" 434 $ taler-wallet-cli --wallet-db=mydb.sqlite3 run-until-done 435 436 437 To test refreshing, force a refresh: 438 439 .. code-block:: console 440 441 $ taler-wallet-cli --wallet-db=mydb.sqlite3 advanced force-refresh "$coin_pub" 442 443 444 To test zombie coins, use the timetravel option. It **must** be passed to the 445 top-level command and not the subcommand: 446 447 .. code-block:: console 448 449 # Update exchange /keys with time travel, value in microseconds 450 $ taler-wallet-cli --timetravel=1000000 --wallet-db=mydb.sqlite3 \ 451 exchanges update -f https://exchange.int.taler.net/ 452 453 454 Integration Test and Fault Injection Framework 455 ---------------------------------------------- 456 457 This section describes the current approach to integration testing in the wallet. 458 459 It's all based on a TypeScript harness process, which itself implements 460 the fault injection proxy (async and in-process)! 461 462 The new approach consists of the following parts: 463 464 1. A strongly typed, convenient helper library to easily set up and run 465 arbitrary Taler deployments and run test cases. These components plug 466 together as easily as lego bricks, even with multiple 467 exchanges/merchants/banks/etc. Logs and clean shutdown (even on SIGINT 468 or errors) are handled properly. (Support for auditors is still pending 469 but needed to fully test the wallet.) 470 471 This is how a simple withdrawal and payment test case looks like: 472 `<https://git.taler.net/taler-typescript-core.git/tree/packages/taler-harness/src/integrationtests/test-payment.ts>`__ 473 474 (What's particularly nice is that all our docs contain TypeScript 475 definitions for all API request bodies. So just copying them into the 476 test harness gives us auto-completion and compile-time checks to avoid 477 typos. The wallet's JSON validation machinery is also re-used.) 478 479 2. A fault injection proxy that can be plugged between the services 480 and/or the wallet. It runs alongside the test harness, and can thus can 481 use arbitrary custom logic. There's no dependency for it other than 482 built-in Node.JS libraries. Simple fault injections are just as easy to 483 set up as with the twister. 484 485 The following test case (a) logs all requests and responses to the test 486 harness stdout and (b) at a certain point, starts dropping the next 10 487 requests to the exchange (testing the wallet's retry logic): 488 489 `<https://git.taler.net/taler-typescript-core.git/tree/packages/taler-harness/src/integrationtests/test-payment-fault.ts#n165>`__ 490 491 3. All util functionality from JS wallet-core, such as the Taler crypto, 492 amount/date/etc. handling and JSON parsing/validation (the wallet is now 493 more modular and easier to use as a library) can be used in the 494 integration tests, even if a different wallet (Kotlin, whatever) is 495 tested via the CLI. 496 497 4. A bunch of test cases that use (1)-(3). These are *significantly* 498 more readable and hackable than other test approaches we had, while 499 allowing for more complex scenarios. There are still way too few tests 500 though! 501 502 5. A test runner (written in bash) that runs test cases based on a glob 503 pattern and reports the results. 504 505 Injecting a fault is as easy as: 506 507 .. code:: ts 508 509 // Set up test case 510 [...] 511 512 exchangeProxy.addFault({ 513 beforeResponse(ctx: FaultInjectionResponseContext) { 514 if (cond1) { // Drop some responses 515 ctx.dropResponse = true; 516 return; 517 } else if (cond2) { // modify some others 518 ctx.responseBody = Buffer.from(`{"oops": true}`, "utf-8"); 519 return; 520 } 521 // Other things that can be modified: 522 // - drop/modify the request, not just the response 523 // - modify headers 524 // - modify status codes 525 } 526 }); 527 528 await doSomethingWithTheWallet(); 529 530 exchangeProxy.clearFault(); 531 532 await doMoreWithTheWallet(); 533 534 535 To make the configuration easy, an ``ExchangeService`` (or ``MerchantService``, 536 ``BankService`` etc.) can be wrapped in a ``FaultInjectedExchangeService``, 537 which implements the ``ExchangeServiceInterface``: 538 539 .. code:: ts 540 541 // create exchange and two merchants 542 const exchange = await setupExchange(...); 543 const merchant1 = ...; 544 const merchant2 = ...; 545 546 // Add exchange to merchant-accepted exchanges. 547 // This will adjust the config. 548 merchant1.addExchange(exchange); 549 550 // Wrap exchange in fault injection proxy 551 const faultInjectedExchange: ExchangeServiceInterface 552 = new FaultInjectedExchangeService(t, exchange1, 8085); 553 554 // Merchant 2 talks to the exchange over fault injection, 555 // and thus must use the "twisted" base URL. 556 merchant2.addExchange(faultInjectedExchange); 557 558 559 The package for the integration tests is here: 560 561 `<https://git.taler.net/wallet-core.git/tree/packages/taler-harness>`__ 562 563 The integration tests are run via the ``taler-harness`` tool. 564 565 .. code:: sh 566 567 ./bootstrap && ./configure --prefix=... && make install 568 taler-harness run-integrationtests 569 570 571 Transaction lifecycle contract 572 ============================== 573 574 Wallet transactions expose their current state, user-visible information, and 575 permitted ``txActions`` through the wallet API. UIs MUST derive buttons from 576 ``txActions`` rather than infer them from a locally duplicated transition 577 table. The common lifecycle classes are: 578 579 * ``pending`` and ``finalizing``: wallet processing is active; 580 * ``dialog``: an explicit user decision is required; 581 * ``suspended``: processing was paused and may offer resume or deletion; 582 * ``aborting``: compensating/refund work is active; 583 * ``done``: the intended operation completed; 584 * ``failed`` or ``aborted``: processing ended unsuccessfully, with the reason 585 carried by the transaction response; and 586 * ``deleted``: the history entry is hidden, while cryptographic records still 587 needed for spend, recoup, or auditing may remain. 588 589 Network retries and internal self-transitions need not change the lifecycle 590 class. An implementation can expose error details while remaining pending. 591 Deletion is not cancellation: a transaction must first use an offered abort 592 action when protocol-side compensation is necessary. 593 594 595 KYC-gated operation retry 596 ========================= 597 598 Withdrawals, deposits, and peer-to-peer operations use one common retry 599 algorithm when an exchange denies progress for KYC or AML reasons: 600 601 #. Attempt the operation unless the most recent denial is less than one hour 602 old. Success ends processing; HTTP 451 records the denial and whether the 603 account authorization was invalid; unrelated failures back off. 604 #. Query the operation's ``/kyc-check/`` endpoint. The first request does not 605 long-poll. Later requests long-poll for account authorization, rule, or AML 606 changes and include ``min_rule`` when a rule generation is known. 607 #. Compare the HTTP status, Taler error code, and rule generation with the 608 previous response. An unchanged response backs off. HTTP 200 or 204 609 retries the operation; HTTP 202 evaluates the exposed limits; HTTP 403 can 610 switch to a requested account key when the wallet owns it; HTTP 404 either 611 requests new authorization or evaluates default limits. 612 #. A ``verboten`` limit permanently fails the transaction. A time-window 613 limit schedules the next attempt for the first permitted time. Otherwise 614 the wallet immediately retries the operation. 615 616 Manual review of KYC instructions, a new authorization transfer, or relevant 617 progress in another operation resets the retry delay. Repeated network 618 timeouts still use exponential backoff even when the HTTP long-poll duration 619 is shortened to fit middleware limits. 620 621 622 Exchange base-URL migration 623 =========================== 624 625 Wallet-core maintains explicit ``old URL -> new URL`` migration plans. A plan 626 is applied only after the old exchange is unavailable or reports a mismatching 627 canonical ``base_url`` and the new URL returns a valid ``/keys`` response whose 628 ``base_url`` matches that new URL. Applying a plan atomically replaces stored 629 references and records the old URL, new URL, and migration timestamp. 630 631 Operators must publish wallet support before moving the exchange, allow a 632 client-update grace period, migrate the database and optional security-module 633 keys, and keep a reverse proxy from the old URL for at least the validity of 634 the last old ``/keys`` response. Merchants must configure the new URL 635 explicitly; wallet migration plans do not rewrite merchant configuration. 636 637 638 IBAN and BBAN presentation 639 ========================== 640 641 The wallet API converts between the protocol's ``payto://iban`` representation 642 and a user-facing account field. ``convertIbanAccountFieldToPayto`` accepts an 643 IBAN or the currency's supported BBAN form and returns the normalized payto 644 URI plus the detected entry type. ``convertIbanPaytoToAccountField`` performs 645 the reverse conversion. Deposit wire types advertise ``preferredEntryType`` 646 so UIs do not maintain a separate currency table. 647 648 HUF accounts use BBAN entry/display for production ``iban`` wire targets. The 649 CHF BBAN mapping is reserved for the wallet development experiment. A BBAN 650 field must also accept a pasted full IBAN. Protocol messages continue to use 651 the normalized payto URI; BBAN is a presentation and entry convention only. 652 653 654 Diagnostics export privacy 655 ========================== 656 657 ``getDiagnostics`` produces support information suitable for saving or 658 sharing without exporting the wallet database. The response MUST NOT contain 659 private keys or other secret key material. Account identifiers such as IBANs 660 must be truncated to at most six characters, and user names or equivalent 661 identifiers must be removed or truncated. Adding fields to the response 662 requires a privacy review against these invariants. The diagnostics action is 663 available outside developer mode because it is the preferred alternative to a 664 database export. 665 666 667 Coin selection 668 ============== 669 670 For one exchange, wallet-core selects eligible coins as follows: 671 672 #. Traverse denominations from smallest to largest and add coins until their 673 value covers the target, using the earliest-expiring coins first within a 674 denomination. 675 #. Traverse selected denominations from largest to smallest and remove coins 676 whenever the remainder still covers the target. Obtain change from the 677 smallest indispensable coin when needed. 678 #. When customer-paid fees remain above the merchant allowance and the wallet 679 is not imbalanced, replace groups of small coins with equivalent larger 680 coins until fees fall below the allowance or no useful replacement exists. 681 682 A wallet is considered imbalanced for this step when it holds, on average, 683 more than five times the denomination ratio in coins per denomination, 684 excluding the largest denomination. This keeps selection linear, spends old 685 coins first, and limits small-coin accumulation. Multiple-exchange selection 686 is outside this algorithm and must be handled by a higher-level decision. 687 688 689 Wallet color roles 690 ================== 691 692 Wallet UIs use semantic theme roles instead of literal colors in components. 693 Use roles such as ``primary`` and ``onPrimary`` for an accent and its 694 foreground, the corresponding ``Container`` pair for filled surfaces, and 695 ``error``, ``warning``, and ``success`` roles for feedback. Surface, 696 background, outline, and foreground roles must likewise be paired by meaning; 697 do not choose a role merely because its current hex value looks suitable. 698 699 Every component must obtain roles from the platform theme so light and dark 700 modes can switch without component-specific branches. New role pairs and 701 overrides require WCAG 2.1 AA contrast verification in both modes, including 702 disabled, selected, focused, and error states. Native and WebExtension 703 implementations may encode themes differently, but should retain the same 704 semantic names and intended hierarchy. The evolving palette and adoption 705 status are recorded in :doc:`../design-documents/066-wallet-color-scheme`. 706 707 708 Wallet database migrations 709 ========================== 710 711 Wallet database upgrades are automatic and must preserve the previous data 712 until the new representation is known to be usable. The browser wallet uses 713 an IndexedDB metadata database to identify the active major database and a 714 separately named major-version database for wallet records. This indirection 715 allows a major migration to build a new database without destroying the old 716 one first. 717 718 IndexedDB changes use three mechanisms: 719 720 * A major migration creates a new major-version database and explicitly moves 721 data. This is reserved for changes that cannot be expressed safely in an 722 IndexedDB upgrade transaction; a backup export/import cycle is preferred 723 when practical. 724 * A minor schema migration adds or removes object stores or indexes by 725 changing the schema declaration and its ``versionAdded`` metadata. 726 * An ordered fixup transforms stored values, such as when a mandatory field or 727 serialized representation changes. Fixups can also repair data written by 728 an already deployed buggy version. 729 730 The native SQLite backend has its own ordered schema migrations. Migration 731 from the IndexedDB emulation to native SQLite is a separate, explicit path; 732 backend versions must not be inferred to be interchangeable. Every migration 733 needs tests starting from representative old data, including interrupted and 734 retry scenarios. Current schema declarations and fixup registries in 735 wallet-core are authoritative; the design history is in 736 :doc:`../design-documents/034-wallet-db-migration`. 737 738 739 Dev Experiments 740 =============== 741 742 Dev experiments allow simulating certain scenarios that are difficult to 743 reproduce otherwise. This allows more comprehensive (manual) testing of the 744 UIs. 745 746 You can enable dev experiments by putting the wallet into dev mode and then 747 scanning the QR code for a ``taler://dev-experiment`` URI that specifies the 748 desired dev experiment. 749 750 Faking Protocol Versions 751 ------------------------ 752 753 The ``start-fakeprotover`` dev experiment can be used to fake the protocol 754 version reported by Taler components. It mocks the ``version`` field in the 755 response to ``/config`` or ``/keys``. 756 757 Usage: 758 759 .. code:: none 760 761 taler://dev-experiment/start-fakeprotover?base_url=...&fake_ver=... 762 763 Example: 764 765 .. code:: none 766 767 # Fake version 10:0:0 for https://exchange.demo.taler.net/ 768 taler://dev-experiment/start-fakeprotover?base_url=https%3A%2F%2Fexchange.demo.taler.net%2F&fake_ver=10%3A0%3A0 769 770 771 Faking Transactions 772 ------------------- 773 774 775 **Withdrawal Transaction:** 776 777 .. code:: none 778 779 taler://dev-experiment/add-fake-tx?txType=withdrawal&amountEffective=KUDOS:5 780 781 Options: 782 783 * ``amountEffective``: Mandatory. Effective amount of the withdrawal. 784 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates 785 when in the past the transaction was started (and finished). 786 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``). 787 Exchange base URL used for the withdrwal. 788 789 790 **Payment Transaction:** 791 792 .. code:: none 793 794 taler://dev-experiment/add-fake-tx?txType=payment&amountEffective=KUDOS:5 795 796 Options: 797 798 * ``amountEffective``: Mandatory. Effective amount of the withdrawal. 799 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates 800 when in the past the transaction was started (and finished). 801 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``). 802 Exchange base URL used for the payment. 803 * ``merchantBaseUrl``. Optional (defaults to ``https://backend.demo.taler.net/``). 804 * ``merchantName``. Optional (defaults to ``Test Merchant``). Display name 805 of the merchant in the contract terms of the transaction. 806 * ``summary``. Optional (defaults to ``Test``). Summary in the contract terms of the 807 transaction. 808 809 **Peer Push Credit Transaction:** 810 811 .. code:: none 812 813 taler://dev-experiment/add-fake-tx?txType=peer-push-credit&amountEffective=KUDOS:5 814 815 Options: 816 817 * ``amountEffective``: Mandatory. Effective amount of the withdrawal. 818 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates 819 when in the past the transaction was started (and finished). 820 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``). 821 Exchange base URL used for the payment. 822 * ``summary``. Optional (defaults to ``Test``). Summary in the contract terms of the 823 transaction. 824 825 **Peer Push Debit Transaction:** 826 827 .. code:: none 828 829 taler://dev-experiment/add-fake-tx?txType=peer-push-debit&amountEffective=KUDOS:5 830 831 Options: 832 833 * ``amountEffective``: Mandatory. Effective amount of the withdrawal. 834 * ``tRel``: Optional (defaults to ``0s``). Relative time that indicates 835 when in the past the transaction was started (and finished). 836 * ``exchangeBaseUrl``. Optional (defaults to ``https://exchange.demo.taler.net``). 837 Exchange base URL used for the payment. 838 * ``summary``. Optional (defaults to ``Test``). Summary in the contract terms of the 839 transaction.